Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/resource2/src/ois/linux/EventHelpers.cpp @ 5668

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

Updated OIS library (still 1.2, but CVS version).
There have been some little fixes and support for force feedback on Linux (but this doesn't concern us for now…)

  • Property svn:eol-style set to native
File size: 11.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 "linux/EventHelpers.h"
24#include "linux/LinuxPrereqs.h"
25#include "linux/LinuxForceFeedback.h"
26#include "OISException.h"
27#include "OISJoyStick.h"
28
29#include <linux/input.h>
30#include <cstring>
31
32//#define OIS_LINUX_JOY_DEBUG
33
34#ifdef OIS_LINUX_JOY_DEBUG
35# include <iostream>
36#endif
37
38using namespace std;
39using namespace OIS;
40
41class DeviceComponentInfo
42{
43public:
44        vector<int> buttons, relAxes, absAxes, hats;
45};
46
47bool inline isBitSet(unsigned char bits[], unsigned int bit)
48{
49  return (bits[(bit)/(sizeof(unsigned char)*8)] >> ((bit)%(sizeof(unsigned char)*8))) & 1;
50}
51
52//-----------------------------------------------------------------------------//
53DeviceComponentInfo getComponentInfo( int deviceID )
54{
55        unsigned char ev_bits[1 + EV_MAX/8/sizeof(unsigned char)];
56        memset( ev_bits, 0, sizeof(ev_bits) );
57
58        //Read "all" (hence 0) components of the device
59#ifdef OIS_LINUX_JOY_DEBUG
60        cout << "EventUtils::getComponentInfo(" << deviceID
61                 << ") : Reading device events features" << endl;
62#endif
63        if (ioctl(deviceID, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1)
64                OIS_EXCEPT( E_General, "Could not read device events features");
65
66        DeviceComponentInfo components;
67
68        for (int i = 0; i < EV_MAX; i++)
69        {
70                if( isBitSet(ev_bits, i) )
71                {
72                    // Absolute axis.
73                    if(i == EV_ABS)
74                        {
75                            unsigned char abs_bits[1 + ABS_MAX/8/sizeof(unsigned char)];
76                            memset( abs_bits, 0, sizeof(abs_bits) );
77
78#ifdef OIS_LINUX_JOY_DEBUG
79                                cout << "EventUtils::getComponentInfo(" << deviceID
80                                         << ") : Reading device absolute axis features" << endl;
81#endif
82
83                                if (ioctl(deviceID, EVIOCGBIT(i, sizeof(abs_bits)), abs_bits) == -1)
84                                    OIS_EXCEPT( E_General, "Could not read device absolute axis features");
85
86                                for (int j = 0; j < ABS_MAX; j++)
87                                {
88                                    if( isBitSet(abs_bits, j) )
89                                        {
90                                                //input_absinfo abInfo;
91                                                //ioctl( fd, EVIOCGABS(j), abInfo );
92                                                if( j >= ABS_HAT0X && j <= ABS_HAT3Y )
93                                                {
94                                                        components.hats.push_back(j);
95                                                }
96                                                else
97                                                {
98                                                        components.absAxes.push_back(j);
99                                                        //input_absinfo absinfo;
100                                                        //ioctl(deviceID, EVIOCGABS(j), &absinfo);
101                                                        //We cannot actually change these values :|
102                                                        //absinfo.minimum = JoyStick::MIN_AXIS;
103                                                        //absinfo.maximum = JoyStick::MAX_AXIS;
104                                                        //ioctl(deviceID, EVIOCSABS(j), &absinfo);
105                                                }
106                                        }
107                                }
108                        }
109                        else if(i == EV_REL)
110                        {
111                            unsigned char rel_bits[1 + REL_MAX/8/sizeof(unsigned char)];
112                                memset( rel_bits, 0, sizeof(rel_bits) );
113                               
114#ifdef OIS_LINUX_JOY_DEBUG
115                                cout << "EventUtils::getComponentInfo(" << deviceID
116                                         << ") : Reading device relative axis features" << endl;
117#endif
118
119                                if (ioctl(deviceID, EVIOCGBIT(i, sizeof(rel_bits)), rel_bits) == -1)
120                                    OIS_EXCEPT( E_General, "Could not read device relative axis features");
121                               
122                                for (int j = 0; j < REL_MAX; j++)
123                                {
124                                    if( isBitSet(rel_bits, j) )
125                                        {
126                                            components.relAxes.push_back(j);
127                                        }
128                                }
129                        }
130                        else if(i == EV_KEY)
131                        {
132                            unsigned char key_bits[1 + KEY_MAX/8/sizeof(unsigned char)];
133                                memset( key_bits, 0, sizeof(key_bits) );
134                               
135#ifdef OIS_LINUX_JOY_DEBUG
136                                cout << "EventUtils::getComponentInfo(" << deviceID
137                                         << ") : Reading device buttons features" << endl;
138#endif
139
140                                if (ioctl(deviceID, EVIOCGBIT(i, sizeof(key_bits)), key_bits) == -1)
141                                    OIS_EXCEPT( E_General, "Could not read device buttons features");
142                               
143                                for (int j = 0; j < KEY_MAX; j++)
144                                {
145                                    if( isBitSet(key_bits, j) )
146                                        {
147                                            components.buttons.push_back(j);
148                                        }
149                                }
150                        }
151                }
152        }
153
154        return components;
155}
156
157//-----------------------------------------------------------------------------//
158bool EventUtils::isJoyStick( int deviceID, JoyStickInfo &js )
159{
160        if( deviceID == -1 ) 
161                OIS_EXCEPT( E_General, "Error with File Descriptor" );
162
163        DeviceComponentInfo info = getComponentInfo( deviceID );
164
165        int buttons = 0;
166        bool joyButtonFound = false;
167        js.button_map.clear();
168
169        #ifdef OIS_LINUX_JOY_DEBUG
170        cout << endl << "Displaying ButtonMapping Status:" << endl;
171        #endif
172        for(vector<int>::iterator i = info.buttons.begin(), e = info.buttons.end(); i != e; ++i )
173        {
174                //Check to ensure we find at least one joy only button
175                if( (*i >= BTN_JOYSTICK && *i < BTN_GAMEPAD) 
176                        || (*i >= BTN_GAMEPAD && *i < BTN_DIGI)
177                        || (*i >= BTN_WHEEL && *i < KEY_OK) )
178                        joyButtonFound = true;
179
180                js.button_map[*i] = buttons++;
181
182                #ifdef OIS_LINUX_JOY_DEBUG
183                  cout << "Button Mapping ID (hex): " << hex << *i
184                           << " OIS Button Num: " << dec << buttons-1 << endl;
185                #endif
186        }
187        #ifdef OIS_LINUX_JOY_DEBUG
188        cout << endl;
189        #endif
190
191        //Joy Buttons found, so it must be a joystick or pad
192        if( joyButtonFound )
193        {
194                js.joyFileD = deviceID;
195                js.vendor = getName(deviceID);
196                js.buttons = buttons;
197                js.axes = info.relAxes.size() + info.absAxes.size();
198                js.hats = info.hats.size();
199                #ifdef OIS_LINUX_JOY_DEBUG
200                  cout << endl << "Device name:" << js.vendor << endl;
201                  cout << "Device unique Id:" << getUniqueId(deviceID) << endl;
202                  cout << "Device physical location:" << getPhysicalLocation(deviceID) << endl;
203                #endif
204
205                //Map the Axes
206                #ifdef OIS_LINUX_JOY_DEBUG
207                  cout << endl << "Displaying AxisMapping Status:" << endl;
208                #endif
209                int axes = 0;
210                for(vector<int>::iterator i = info.absAxes.begin(), e = info.absAxes.end(); i != e; ++i )
211                {
212                        js.axis_map[*i] = axes;
213
214#ifdef OIS_LINUX_JOY_DEBUG
215                        cout << "EventUtils::isJoyStick(" << deviceID
216                                          << ") : Reading device absolute axis #" << *i << " features" << endl;
217#endif
218
219                        input_absinfo absinfo;
220                        if (ioctl(deviceID, EVIOCGABS(*i), &absinfo) == -1)
221                                OIS_EXCEPT( E_General, "Could not read device absolute axis features");
222                        js.axis_range[axes] = Range(absinfo.minimum, absinfo.maximum);
223
224                        #ifdef OIS_LINUX_JOY_DEBUG
225                          cout << "Axis Mapping ID (hex): " << hex << *i
226                                   << " OIS Axis Num: " << dec << axes << endl;
227                        #endif
228
229                        ++axes;
230                }
231        }
232
233        return joyButtonFound;
234}
235
236//-----------------------------------------------------------------------------//
237string EventUtils::getName( int deviceID )
238{
239#ifdef OIS_LINUX_JOY_DEBUG
240        cout << "EventUtils::getName(" << deviceID
241                 << ") : Reading device name" << endl;
242#endif
243
244        char name[OIS_DEVICE_NAME];
245        if (ioctl(deviceID, EVIOCGNAME(OIS_DEVICE_NAME), name) == -1)
246                OIS_EXCEPT( E_General, "Could not read device name");
247        return string(name);
248}
249
250//-----------------------------------------------------------------------------//
251string EventUtils::getUniqueId( int deviceID )
252{
253#ifdef OIS_LINUX_JOY_DEBUG
254        cout << "EventUtils::getUniqueId(" << deviceID
255                 << ") : Reading device unique Id" << endl;
256#endif
257
258#define OIS_DEVICE_UNIQUE_ID 128
259        char uId[OIS_DEVICE_UNIQUE_ID];
260        if (ioctl(deviceID, EVIOCGUNIQ(OIS_DEVICE_UNIQUE_ID), uId) == -1)
261                OIS_EXCEPT( E_General, "Could not read device unique Id");
262        return string(uId);
263}
264
265//-----------------------------------------------------------------------------//
266string EventUtils::getPhysicalLocation( int deviceID )
267{
268#ifdef OIS_LINUX_JOY_DEBUG
269        cout << "EventUtils::getPhysicalLocation(" << deviceID
270                 << ") : Reading device physical location" << endl;
271#endif
272
273#define OIS_DEVICE_PHYSICAL_LOCATION 128
274        char physLoc[OIS_DEVICE_PHYSICAL_LOCATION];
275        if (ioctl(deviceID, EVIOCGPHYS(OIS_DEVICE_PHYSICAL_LOCATION), physLoc) == -1)
276                OIS_EXCEPT( E_General, "Could not read device physical location");
277        return string(physLoc);
278}
279
280//-----------------------------------------------------------------------------//
281void EventUtils::enumerateForceFeedback( int deviceID, LinuxForceFeedback** ff )
282{
283        //Linux Event to OIS Event Mappings
284        map<int, Effect::EType> typeMap;
285        typeMap[FF_CONSTANT] = Effect::Constant;
286        typeMap[FF_RAMP]     = Effect::Ramp;
287        typeMap[FF_SPRING]   = Effect::Spring;
288        typeMap[FF_FRICTION] = Effect::Friction;
289        typeMap[FF_SQUARE]   = Effect::Square;
290        typeMap[FF_TRIANGLE] = Effect::Triangle;
291        typeMap[FF_SINE]     = Effect::Sine;
292        typeMap[FF_SAW_UP]   = Effect::SawToothUp;
293        typeMap[FF_SAW_DOWN] = Effect::SawToothDown;
294        typeMap[FF_DAMPER]   = Effect::Damper;
295        typeMap[FF_INERTIA]  = Effect::Inertia;
296        typeMap[FF_CUSTOM]   = Effect::Custom;
297
298        map<int, Effect::EForce> forceMap;
299        forceMap[FF_CONSTANT] = Effect::ConstantForce;
300        forceMap[FF_RAMP]     = Effect::RampForce;
301        forceMap[FF_SPRING]   = Effect::ConditionalForce;
302        forceMap[FF_FRICTION] = Effect::ConditionalForce;
303        forceMap[FF_SQUARE]   = Effect::PeriodicForce;
304        forceMap[FF_TRIANGLE] = Effect::PeriodicForce;
305        forceMap[FF_SINE]     = Effect::PeriodicForce;
306        forceMap[FF_SAW_UP]   = Effect::PeriodicForce;
307        forceMap[FF_SAW_DOWN] = Effect::PeriodicForce;
308        forceMap[FF_DAMPER]   = Effect::ConditionalForce;
309        forceMap[FF_INERTIA]  = Effect::ConditionalForce;
310        forceMap[FF_CUSTOM]   = Effect::CustomForce;
311
312        //Remove any previously existing memory and create fresh
313        removeForceFeedback( ff );
314        *ff = new LinuxForceFeedback(deviceID);
315
316        //Read overall force feedback features
317        unsigned char ff_bits[1 + FF_MAX/8/sizeof(unsigned char)];
318        memset(ff_bits, 0, sizeof(ff_bits));
319
320#ifdef OIS_LINUX_JOY_DEBUG
321        cout << "EventUtils::enumerateForceFeedback(" << deviceID
322                 << ") : Reading device force feedback features" << endl;
323#endif
324
325        if (ioctl(deviceID, EVIOCGBIT(EV_FF, sizeof(ff_bits)), ff_bits) == -1)
326                OIS_EXCEPT( E_General, "Could not read device force feedback features");
327
328
329    #ifdef OIS_LINUX_JOY_DEBUG
330        cout << "FF bits: " << hex;
331        for (int i = 0; i < sizeof(ff_bits); i++)
332                cout << (int)ff_bits[i];
333        cout << endl << dec;
334    #endif
335
336        //FF Axes
337        //if( isBitSet(ff_bits, ABS_X) ) //X Axis
338        //if( isBitSet(ff_bits, ABS_Y) ) //Y Axis
339        //if( isBitSet(ff_bits, ABS_WHEEL) ) //Wheel
340
341        //FF Effects
342        for( int effect = FF_EFFECT_MIN; effect <= FF_WAVEFORM_MAX; effect++ )
343        {
344                // The RUMBLE force type is ignored, as periodic force one is more powerfull.
345                // The PERIODIC force type is processed later, for each associated periodic effect type.
346                if (effect == FF_RUMBLE || effect == FF_PERIODIC)
347                        continue;
348
349                if(isBitSet(ff_bits, effect))
350                {
351                        #ifdef OIS_LINUX_JOY_DEBUG
352                    cout << "  Effect Type: " << Effect::getEffectTypeName(typeMap[effect]) << endl;
353                        #endif
354
355                        (*ff)->_addEffectTypes( forceMap[effect], typeMap[effect] );
356                }
357        }
358
359        //FF device properties
360        if (isBitSet(ff_bits, FF_GAIN))
361                (*ff)->_setGainSupport(true);
362               
363        if (isBitSet(ff_bits, FF_AUTOCENTER))
364                (*ff)->_setAutoCenterSupport(true);
365
366        //Check to see if any effects were added, else destroy the pointer
367        const ForceFeedback::SupportedEffectList &list = (*ff)->getSupportedEffects();
368        if( list.size() == 0 )
369                removeForceFeedback( ff );
370}
371
372//-----------------------------------------------------------------------------//
373void EventUtils::removeForceFeedback( LinuxForceFeedback** ff )
374{
375        delete *ff;
376        *ff = 0;
377}
Note: See TracBrowser for help on using the repository browser.