Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 7236 was 5781, checked in by rgrieder, 15 years ago

Reverted trunk again. We might want to find a way to delete these revisions again (x3n's changes are still available as diff in the commit mails).

  • Property svn:eol-style set to native
File size: 13.0 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        if (ff_device)
85        {
86                delete ff_device;
87                ff_device = 0;
88        }
89
90        // Create direct input joystick device.
91        if(FAILED(mDirectInput->CreateDevice(deviceGuid, &mJoyStick, NULL)))
92                OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> Could not initialize joy device!");
93
94        // Set DIJoystick2 data format.
95        if(FAILED(mJoyStick->SetDataFormat(&c_dfDIJoystick2)))
96                OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> data format error!");
97
98        // Set cooperative level as specified when creating input manager.
99        HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
100        if(FAILED(mJoyStick->SetCooperativeLevel( hwin, coopSetting)))
101                OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> failed to set cooperation level!");
102
103        // Set buffer size.
104        DIPROPDWORD dipdw;
105        dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
106        dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
107        dipdw.diph.dwObj        = 0;
108        dipdw.diph.dwHow        = DIPH_DEVICE;
109        dipdw.dwData            = JOYSTICK_DX_BUFFERSIZE;
110
111        if( FAILED(mJoyStick->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)) )
112                OIS_EXCEPT( E_General, "Win32JoyStick::_initialize >> Failed to set buffer size property" );
113
114        // Enumerate all axes/buttons/sliders/force feedback/etc before aquiring
115        _enumerate();
116
117        mState.clear();
118
119        capture();
120}
121
122//--------------------------------------------------------------------------------------------------//
123void Win32JoyStick::_enumerate()
124{
125        // Get joystick capabilities.
126        mDIJoyCaps.dwSize = sizeof(DIDEVCAPS);
127        if( FAILED(mJoyStick->GetCapabilities(&mDIJoyCaps)) )
128                OIS_EXCEPT( E_General, "Win32JoyStick::_enumerate >> Failed to get capabilities" );
129
130        // => Number of POVs
131        mPOVs = (short)mDIJoyCaps.dwPOVs;
132
133        // => Number of buttons and axes.
134        mState.mButtons.resize(mDIJoyCaps.dwButtons);
135        mState.mAxes.resize(mDIJoyCaps.dwAxes);
136
137        // Enumerate all Force Feedback effects (if any)
138        mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL);
139
140        //Reset the axis mapping enumeration value
141        _AxisNumber = 0;
142
143        // Enumerate and set axis constraints (and check FF Axes)
144        mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS);
145}
146
147//--------------------------------------------------------------------------------------------------//
148BOOL CALLBACK Win32JoyStick::DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef)
149{
150        Win32JoyStick* _this = (Win32JoyStick*)pvRef;
151
152        //Setup mappings
153        DIPROPPOINTER diptr;
154        diptr.diph.dwSize       = sizeof(DIPROPPOINTER);
155        diptr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
156        diptr.diph.dwHow        = DIPH_BYID;
157        diptr.diph.dwObj        = lpddoi->dwType;
158        //Add a magic number to recognise we set seomthing
159        diptr.uData             = 0x13130000 | _this->_AxisNumber;
160
161        //Check if axis is slider, if so, do not treat as regular axis
162        if(GUID_Slider == lpddoi->guidType)
163        {
164                ++_this->mSliders;
165
166                //Decrease Axes, since this slider shows up in a different place
167                _this->mState.mAxes.pop_back();
168        }
169        else if (FAILED(_this->mJoyStick->SetProperty(DIPROP_APPDATA, &diptr.diph)))
170        {       //If for some reason we could not set needed user data, just ignore this axis
171                return DIENUM_CONTINUE;
172        }
173
174        //Increase for next time through
175        if(GUID_Slider != lpddoi->guidType)
176                _this->_AxisNumber += 1;
177
178        //Set range
179        DIPROPRANGE diprg;
180        diprg.diph.dwSize       = sizeof(DIPROPRANGE);
181        diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
182        diprg.diph.dwHow        = DIPH_BYID;
183        diprg.diph.dwObj        = lpddoi->dwType;
184        diprg.lMin              = MIN_AXIS;
185        diprg.lMax              = MAX_AXIS;
186
187        if (FAILED(_this->mJoyStick->SetProperty(DIPROP_RANGE, &diprg.diph)))
188                OIS_EXCEPT( E_General, "Win32JoyStick::_DIEnumDeviceObjectsCallback >> Failed to set min/max range property" );
189
190        //Check if FF Axes, and if so, increment counter
191        if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 )
192        {
193                if( _this->ff_device )
194                {
195                        _this->ff_device->_addFFAxis();
196                }
197        }
198
199        //Force the flags for gain and auto-center support to true,
200        //as DInput has no API to query the device for these capabilities
201        //(the only way to know is to try them ...)
202        if( _this->ff_device )
203        {
204            _this->ff_device->_setGainSupport(true);
205            _this->ff_device->_setAutoCenterSupport(true);
206        }
207
208        return DIENUM_CONTINUE;
209}
210
211//--------------------------------------------------------------------------------------------------//
212BOOL CALLBACK Win32JoyStick::DIEnumEffectsCallback(LPCDIEFFECTINFO pdei, LPVOID pvRef)
213{
214        Win32JoyStick* _this = (Win32JoyStick*)pvRef;
215
216        //Create the FF instance only after we know there is at least one effect type
217        if( _this->ff_device == 0 )
218          _this->ff_device = new Win32ForceFeedback(_this->mJoyStick, &_this->mDIJoyCaps);
219
220        _this->ff_device->_addEffectSupport( pdei );
221
222        return DIENUM_CONTINUE;
223}
224
225//--------------------------------------------------------------------------------------------------//
226void Win32JoyStick::capture()
227{
228        DIDEVICEOBJECTDATA diBuff[JOYSTICK_DX_BUFFERSIZE];
229        DWORD entries = JOYSTICK_DX_BUFFERSIZE;
230
231        // Poll the device to read the current state
232        HRESULT hr = mJoyStick->Poll();
233        if( hr == DI_OK )
234                hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
235
236        if( hr != DI_OK )
237        {
238                hr = mJoyStick->Acquire();
239                while( hr == DIERR_INPUTLOST )
240                        hr = mJoyStick->Acquire();
241
242                // Poll the device to read the current state
243            mJoyStick->Poll();
244                hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
245                //Perhaps the user just tabbed away
246                if( FAILED(hr) )
247                        return;
248        }
249
250        bool axisMoved[24] = {false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,
251                                                  false,false,false,false,false,false,false,false};
252        bool sliderMoved[4] = {false,false,false,false};
253
254        //Loop through all the events
255        for(unsigned int i = 0; i < entries; ++i)
256        {
257                //This may seem outof order, but is in order of the way these variables
258                //are declared in the JoyStick State 2 structure.
259                switch(diBuff[i].dwOfs)
260                {
261                //------ slider -//
262                case DIJOFS_SLIDER0(0):
263                        sliderMoved[0] = true;
264                        mState.mSliders[0].abX = diBuff[i].dwData;
265                        break;
266                case DIJOFS_SLIDER0(1):
267                        sliderMoved[0] = true;
268                        mState.mSliders[0].abY = diBuff[i].dwData;
269                        break;
270                //----- Max 4 POVs Next ---------------//
271                case DIJOFS_POV(0):
272                        if(!_changePOV(0,diBuff[i]))
273                                return;
274                        break;
275                case DIJOFS_POV(1):
276                        if(!_changePOV(1,diBuff[i]))
277                                return;
278                        break;
279                case DIJOFS_POV(2):
280                        if(!_changePOV(2,diBuff[i]))
281                                return;
282                        break;
283                case DIJOFS_POV(3):
284                        if(!_changePOV(3,diBuff[i]))
285                                return;
286                        break;
287                case DIJOFS_SLIDER1(0):
288                        sliderMoved[1] = true;
289                        mState.mSliders[1].abX = diBuff[i].dwData;
290                        break;
291                case DIJOFS_SLIDER1(1):
292                        sliderMoved[1] = true;
293                        mState.mSliders[1].abY = diBuff[i].dwData;
294                        break;
295                case DIJOFS_SLIDER2(0):
296                        sliderMoved[2] = true;
297                        mState.mSliders[2].abX = diBuff[i].dwData;
298                        break;
299                case DIJOFS_SLIDER2(1):
300                        sliderMoved[2] = true;
301                        mState.mSliders[2].abY = diBuff[i].dwData;
302                        break;
303                case DIJOFS_SLIDER3(0):
304                        sliderMoved[3] = true;
305                        mState.mSliders[3].abX = diBuff[i].dwData;
306                        break;
307                case DIJOFS_SLIDER3(1):
308                        sliderMoved[3] = true;
309                        mState.mSliders[3].abY = diBuff[i].dwData;
310                        break;
311                //-----------------------------------------//
312                default:
313                        //Handle Button Events Easily using the DX Offset Macros
314                        if( diBuff[i].dwOfs >= DIJOFS_BUTTON(0) && diBuff[i].dwOfs < DIJOFS_BUTTON(128) )
315                        {
316                                if(!_doButtonClick((diBuff[i].dwOfs - DIJOFS_BUTTON(0)), diBuff[i]))
317                                        return;
318                        }
319                        else if((short)(diBuff[i].uAppData >> 16) == 0x1313)
320                        {       //If it was nothing else, might be axis enumerated earlier (determined by magic number)
321                                int axis = (int)(0x0000FFFF & diBuff[i].uAppData); //Mask out the high bit
322                                assert( axis >= 0 && axis < (int)mState.mAxes.size() && "Axis out of range!");
323
324                                if(axis >= 0 && axis < (int)mState.mAxes.size())
325                                {
326                                        mState.mAxes[axis].abs = diBuff[i].dwData;
327                                        axisMoved[axis] = true;
328                                }
329                        }
330
331                        break;
332                } //end case
333        } //end for
334
335        //Check to see if any of the axes values have changed.. if so send events
336        if( mBuffered && mListener && entries > 0 )
337        {
338                JoyStickEvent temp(this, mState);
339
340                //Update axes
341                for( int i = 0; i < 24; ++i )
342                        if( axisMoved[i] )
343                                if( mListener->axisMoved( temp, i ) == false )
344                                        return;
345
346                //Now update sliders
347                for( int i = 0; i < 4; ++i )
348                        if( sliderMoved[i] )
349                                if( mListener->sliderMoved( temp, i ) == false )
350                                        return;
351        }
352}
353
354//--------------------------------------------------------------------------------------------------//
355bool Win32JoyStick::_doButtonClick( int button, DIDEVICEOBJECTDATA& di )
356{
357        if( di.dwData & 0x80 )
358        {
359                mState.mButtons[button] = true;
360                if( mBuffered && mListener )
361                        return mListener->buttonPressed( JoyStickEvent( this, mState ), button );
362        }
363        else
364        {
365                mState.mButtons[button] = false;
366                if( mBuffered && mListener )
367                        return mListener->buttonReleased( JoyStickEvent( this, mState ), button );
368        }
369
370        return true;
371}
372
373//--------------------------------------------------------------------------------------------------//
374bool Win32JoyStick::_changePOV( int pov, DIDEVICEOBJECTDATA& di )
375{
376        //Some drivers report a value of 65,535, instead of —1,
377        //for the center position
378        if(LOWORD(di.dwData) == 0xFFFF)
379        {
380                mState.mPOV[pov].direction = Pov::Centered;
381        }
382        else
383        {
384                switch(di.dwData)
385                {
386                        case 0: mState.mPOV[pov].direction = Pov::North; break;
387                        case 4500: mState.mPOV[pov].direction = Pov::NorthEast; break;
388                        case 9000: mState.mPOV[pov].direction = Pov::East; break;
389                        case 13500: mState.mPOV[pov].direction = Pov::SouthEast; break;
390                        case 18000: mState.mPOV[pov].direction = Pov::South; break;
391                        case 22500: mState.mPOV[pov].direction = Pov::SouthWest; break;
392                        case 27000: mState.mPOV[pov].direction = Pov::West; break;
393                        case 31500: mState.mPOV[pov].direction = Pov::NorthWest; break;
394                }
395        }
396
397        if( mBuffered && mListener )
398                return mListener->povMoved( JoyStickEvent( this, mState ), pov );
399
400        return true;
401}
402
403//--------------------------------------------------------------------------------------------------//
404void Win32JoyStick::setBuffered(bool buffered)
405{
406        mBuffered = buffered;
407}
408
409//--------------------------------------------------------------------------------------------------//
410Interface* Win32JoyStick::queryInterface(Interface::IType type)
411{
412        //Thought about using covariant return type here.. however,
413        //some devices may allow LED light changing, or other interface stuff
414
415        if( ff_device && type == Interface::ForceFeedback )
416                return ff_device;
417        else
418                return 0;
419}
Note: See TracBrowser for help on using the repository browser.