Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/external/ois/linux/EventHelpers.cpp @ 11521

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