00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "linux/EventHelpers.h"
00024 #include "linux/LinuxPrereqs.h"
00025 #include "linux/LinuxForceFeedback.h"
00026 #include "OISException.h"
00027 #include "OISJoyStick.h"
00028
00029 #include <linux/input.h>
00030
00031
00032
00033 #ifdef OIS_LINUX_JOY_DEBUG
00034 # include <iostream>
00035 using namespace std;
00036 #endif
00037
00038 using namespace OIS;
00039
00040 struct DeviceComponentInfo
00041 {
00042 std::vector<int> buttons, relAxes, absAxes, hats;
00043 };
00044
00045 bool inline isBitSet(unsigned long bits[], unsigned int bit)
00046 {
00047 return (bits[bit/(sizeof(long)*8)] >> ((bit)%(sizeof(long)*8))) & 1;
00048 }
00049
00050 DeviceComponentInfo getComponentInfo( int deviceID )
00051 {
00052 unsigned long info[2][((KEY_MAX-1)/(sizeof(long)*8)) +1];
00053 memset( info, 0, sizeof(info) );
00054
00055 DeviceComponentInfo components;
00056
00057
00058 ioctl(deviceID, EVIOCGBIT(0, EV_MAX), info[0]);
00059
00060 for (int i = 0; i < EV_MAX; i++)
00061 {
00062 if( isBitSet(info[0], i) )
00063 {
00064 memset( info[1], 0, sizeof(info) / 2 );
00065 ioctl(deviceID, EVIOCGBIT(i, KEY_MAX), info[1]);
00066 for (int j = 0; j < KEY_MAX; j++)
00067 {
00068 if( isBitSet(info[1], j) )
00069 {
00070 if(i == EV_ABS)
00071 {
00072
00073
00074 if( j >= ABS_HAT0X && j <= ABS_HAT3Y )
00075 {
00076 components.hats.push_back(j);
00077 }
00078 else
00079 {
00080 components.absAxes.push_back(j);
00081
00082
00083
00084
00085
00086
00087 }
00088 }
00089 else if(i == EV_REL)
00090 {
00091 components.relAxes.push_back(j);
00092 }
00093 else if(i == EV_KEY)
00094 {
00095 components.buttons.push_back(j);
00096 }
00097 }
00098 }
00099 }
00100 }
00101
00102 return components;
00103 }
00104
00105
00106 bool EventUtils::isJoyStick( int deviceID, JoyStickInfo &js )
00107 {
00108 if( deviceID == -1 ) OIS_EXCEPT( E_General, "Error with File Descriptor" );
00109
00110 DeviceComponentInfo info = getComponentInfo( deviceID );
00111
00112 int buttons = 0;
00113 bool joyButtonFound = false;
00114 js.button_map.clear();
00115
00116 #ifdef OIS_LINUX_JOY_DEBUG
00117 cout << "\n\nDisplaying ButtonMapping Status:";
00118 #endif
00119 for(std::vector<int>::iterator i = info.buttons.begin(), e = info.buttons.end(); i != e; ++i )
00120 {
00121
00122 if( (*i >= BTN_JOYSTICK && *i <= BTN_THUMBR) || (*i >= BTN_WHEEL && *i <= BTN_GEAR_UP ) )
00123 joyButtonFound = true;
00124
00125 js.button_map[*i] = buttons++;
00126
00127 #ifdef OIS_LINUX_JOY_DEBUG
00128 cout << "\nButton Mapping ID (hex): " << hex << *i << " OIS Button Num: " << dec << (buttons-1);
00129 #endif
00130 }
00131
00132
00133 if( joyButtonFound )
00134 {
00135 js.joyFileD = deviceID;
00136 js.vendor = getName(deviceID);
00137 js.buttons = buttons;
00138 js.axes = info.relAxes.size() + info.absAxes.size();
00139 js.hats = info.hats.size();
00140
00141
00142 #ifdef OIS_LINUX_JOY_DEBUG
00143 cout << "\n\nDisplaying AxisMapping Status:";
00144 #endif
00145 int axes = 0;
00146 for(std::vector<int>::iterator i = info.absAxes.begin(), e = info.absAxes.end(); i != e; ++i )
00147 {
00148 js.axis_map[*i] = axes;
00149
00150 input_absinfo absinfo;
00151 ioctl(deviceID, EVIOCGABS(*i), &absinfo);
00152 js.axis_range[axes] = Range(absinfo.minimum, absinfo.maximum);
00153
00154 #ifdef OIS_LINUX_JOY_DEBUG
00155 cout << "\nAxis Mapping ID (hex): " << hex << *i << " OIS Axis Num: " << dec << axes;
00156 #endif
00157
00158 ++axes;
00159 }
00160 }
00161
00162 return joyButtonFound;
00163 }
00164
00165
00166 std::string EventUtils::getName( int deviceID )
00167 {
00168 char name[OIS_DEVICE_NAME];
00169 ioctl(deviceID, EVIOCGNAME(OIS_DEVICE_NAME), name);
00170 return std::string(name);
00171 }
00172
00173
00174 void EventUtils::enumerateForceFeedback( int deviceID, LinuxForceFeedback** ff )
00175 {
00176
00177 std::map<int, Effect::EType> typeMap;
00178 typeMap[FF_CONSTANT] = Effect::Constant;
00179 typeMap[FF_RAMP] = Effect::Ramp;
00180 typeMap[FF_SPRING] = Effect::Spring;
00181 typeMap[FF_FRICTION] = Effect::Friction;
00182 typeMap[FF_SQUARE] = Effect::Square;
00183 typeMap[FF_TRIANGLE] = Effect::Triangle;
00184 typeMap[FF_SINE] = Effect::Sine;
00185 typeMap[FF_SAW_UP] = Effect::SawToothUp;
00186 typeMap[FF_SAW_DOWN] = Effect::SawToothDown;
00187 typeMap[FF_DAMPER] = Effect::Damper;
00188 typeMap[FF_INERTIA] = Effect::Inertia;
00189 typeMap[FF_CUSTOM] = Effect::Custom;
00190
00191 std::map<int, Effect::EForce> forceMap;
00192 forceMap[FF_CONSTANT] = Effect::ConstantForce;
00193 forceMap[FF_RAMP] = Effect::RampForce;
00194 forceMap[FF_PERIODIC] = Effect::PeriodicForce;
00195 forceMap[FF_CUSTOM] = Effect::CustomForce;
00196
00197
00198 removeForceFeedback( ff );
00199 *ff = new LinuxForceFeedback();
00200
00201 unsigned long info[4] = {0,0,0,0};
00202 unsigned long subinfo[4]= {0,0,0,0};
00203
00204
00205 ioctl(deviceID, EVIOCGBIT(EV_FF, sizeof(long)*4), info);
00206
00207
00208
00209
00210
00211
00212
00213 for( int effect = ABS_WHEEL+1; effect < FF_MAX; effect++ )
00214 {
00215 if(isBitSet(info, effect))
00216 {
00217
00218 memset(subinfo, 0, sizeof(subinfo));
00219
00220 ioctl(deviceID, EVIOCGBIT(effect, sizeof(long)*4), subinfo);
00221 for( int force = 0; force < FF_MAX; force++ )
00222 {
00223 if(isBitSet(subinfo, force))
00224 (*ff)->_addEffectTypes( forceMap[force], typeMap[effect] );
00225 }
00226 }
00227 }
00228
00229
00230 const ForceFeedback::SupportedEffectList &list = (*ff)->getSupportedEffects();
00231 if( list.size() == 0 )
00232 removeForceFeedback( ff );
00233 }
00234
00235
00236 void EventUtils::removeForceFeedback( LinuxForceFeedback** ff )
00237 {
00238 delete *ff;
00239 *ff = 0;
00240 }