| [1505] | 1 | /* | 
|---|
 | 2 | The zlib/libpng License | 
|---|
 | 3 |  | 
|---|
 | 4 | Copyright (c) 2005-2007 Phillip Castaneda (pjcast -- www.wreckedgames.com) | 
|---|
 | 5 |  | 
|---|
 | 6 | This software is provided 'as-is', without any express or implied warranty. In no event will | 
|---|
 | 7 | the authors be held liable for any damages arising from the use of this software. | 
|---|
 | 8 |  | 
|---|
 | 9 | Permission is granted to anyone to use this software for any purpose, including commercial | 
|---|
 | 10 | applications, and to alter it and redistribute it freely, subject to the following | 
|---|
 | 11 | restrictions: | 
|---|
 | 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 "OISConfig.h" | 
|---|
 | 24 |  | 
|---|
 | 25 | #include "linux/LinuxJoyStickEvents.h" | 
|---|
 | 26 | #include "linux/LinuxInputManager.h" | 
|---|
 | 27 | #include "linux/LinuxForceFeedback.h" | 
|---|
 | 28 | #include "linux/EventHelpers.h" | 
|---|
 | 29 |  | 
|---|
 | 30 | #include "OISEvents.h" | 
|---|
 | 31 | #include "OISException.h" | 
|---|
 | 32 |  | 
|---|
 | 33 | #include <fcntl.h>        //Needed to Open a file descriptor | 
|---|
 | 34 | #include <cassert>       | 
|---|
 | 35 | #include <linux/input.h> | 
|---|
 | 36 |  | 
|---|
 | 37 |  | 
|---|
 | 38 | #include <sstream> | 
|---|
| [5695] | 39 | # include <iostream> | 
|---|
 | 40 | using namespace std; | 
|---|
| [1505] | 41 |  | 
|---|
 | 42 | using namespace OIS; | 
|---|
 | 43 |  | 
|---|
 | 44 | //#define OIS_LINUX_JOY_DEBUG | 
|---|
 | 45 |  | 
|---|
 | 46 | //-------------------------------------------------------------------// | 
|---|
 | 47 | LinuxJoyStick::LinuxJoyStick(InputManager* creator, bool buffered, const JoyStickInfo& js) | 
|---|
 | 48 |         : JoyStick(js.vendor, buffered, js.devId, creator) | 
|---|
 | 49 | { | 
|---|
 | 50 |         mJoyStick = js.joyFileD; | 
|---|
 | 51 |  | 
|---|
 | 52 |         mState.mAxes.clear(); | 
|---|
 | 53 |         mState.mAxes.resize(js.axes); | 
|---|
 | 54 |         mState.mButtons.clear(); | 
|---|
 | 55 |         mState.mButtons.resize(js.buttons); | 
|---|
 | 56 |  | 
|---|
 | 57 |         mPOVs = js.hats; | 
|---|
 | 58 |  | 
|---|
 | 59 |         mButtonMap = js.button_map; | 
|---|
 | 60 |         mAxisMap = js.axis_map; | 
|---|
 | 61 |         mRanges = js.axis_range; | 
|---|
 | 62 |  | 
|---|
 | 63 |         ff_effect = 0; | 
|---|
 | 64 | } | 
|---|
 | 65 |  | 
|---|
 | 66 | //-------------------------------------------------------------------// | 
|---|
 | 67 | LinuxJoyStick::~LinuxJoyStick() | 
|---|
 | 68 | { | 
|---|
 | 69 |         EventUtils::removeForceFeedback( &ff_effect ); | 
|---|
 | 70 | } | 
|---|
 | 71 |  | 
|---|
 | 72 | //-------------------------------------------------------------------// | 
|---|
 | 73 | void LinuxJoyStick::_initialize() | 
|---|
 | 74 | { | 
|---|
 | 75 |         //Clear old joy state | 
|---|
 | 76 |         mState.mAxes.resize(mAxisMap.size()); | 
|---|
 | 77 |         mState.clear(); | 
|---|
 | 78 |  | 
|---|
 | 79 |         //This will create and new us a force feedback structure if it exists | 
|---|
 | 80 |         EventUtils::enumerateForceFeedback( mJoyStick, &ff_effect ); | 
|---|
 | 81 |  | 
|---|
 | 82 |         if( mJoyStick == -1 ) | 
|---|
 | 83 |                 OIS_EXCEPT(E_InputDeviceNonExistant, "LinuxJoyStick::_initialize() >> JoyStick Not Found!"); | 
|---|
 | 84 | } | 
|---|
 | 85 |  | 
|---|
 | 86 | //-------------------------------------------------------------------// | 
|---|
 | 87 | void LinuxJoyStick::capture() | 
|---|
 | 88 | { | 
|---|
 | 89 |         static const short POV_MASK[8] = {0,0,1,1,2,2,3,3}; | 
|---|
 | 90 |  | 
|---|
 | 91 |         //Used to determine if an axis has been changed and needs an event | 
|---|
 | 92 |         bool axisMoved[32] = {false, false, false, false, false, false, false, false, false, false, false, false, false, | 
|---|
 | 93 |                                                   false, false, false, false, false, false, false, false, false, false, false, false, false, | 
|---|
 | 94 |                                                   false, false, false, false, false, false}; | 
|---|
 | 95 |  | 
|---|
 | 96 |         //We are in non blocking mode - we just read once, and try to fill up buffer | 
|---|
 | 97 |         input_event js[JOY_BUFFERSIZE]; | 
|---|
| [8351] | 98 |         while(true) | 
|---|
| [1505] | 99 |         { | 
|---|
| [8351] | 100 |                 int ret = read(mJoyStick, &js, sizeof(struct input_event) * JOY_BUFFERSIZE); | 
|---|
 | 101 |         if( ret < 0 ) | 
|---|
| [1505] | 102 |                         break; | 
|---|
| [5695] | 103 |  | 
|---|
| [8351] | 104 |                 //Determine how many whole events re read up | 
|---|
 | 105 |                 ret /= sizeof(struct input_event); | 
|---|
 | 106 |                 for(int i = 0; i < ret; ++i) | 
|---|
| [1505] | 107 |                 { | 
|---|
| [8351] | 108 |                         switch(js[i].type) | 
|---|
| [1505] | 109 |                         { | 
|---|
| [8351] | 110 |                         case EV_KEY:  //Button | 
|---|
 | 111 |                         { | 
|---|
 | 112 |                                 int button = mButtonMap[js[i].code]; | 
|---|
| [5695] | 113 |  | 
|---|
| [8351] | 114 |                                 #ifdef OIS_LINUX_JOY_DEBUG | 
|---|
 | 115 |                                   cout << "\nButton Code: " << js[i].code << ", OIS Value: " << button << endl; | 
|---|
 | 116 |                                 #endif | 
|---|
| [1505] | 117 |  | 
|---|
| [8351] | 118 |                                 //Check to see whether push or released event... | 
|---|
 | 119 |                                 if(js[i].value) | 
|---|
 | 120 |                                 { | 
|---|
 | 121 |                                         mState.mButtons[button] = true; | 
|---|
 | 122 |                                         if( mBuffered && mListener ) | 
|---|
 | 123 |                                                 if(!mListener->buttonPressed(JoyStickEvent(this,mState), button)) return; | 
|---|
| [1505] | 124 |                                 } | 
|---|
 | 125 |                                 else | 
|---|
| [8351] | 126 |                                 { | 
|---|
 | 127 |                                         mState.mButtons[button] = false; | 
|---|
 | 128 |                                         if( mBuffered && mListener ) | 
|---|
 | 129 |                                                 if(!mListener->buttonReleased(JoyStickEvent(this,mState), button)) return; | 
|---|
| [1505] | 130 |                                 } | 
|---|
| [8351] | 131 |                                 break; | 
|---|
| [1505] | 132 |                         } | 
|---|
| [8351] | 133 |  | 
|---|
 | 134 |                         case EV_ABS:  //Absolute Axis | 
|---|
| [1505] | 135 |                         { | 
|---|
| [8351] | 136 |                                 //A Stick (BrakeDefine is the highest possible Axis) | 
|---|
 | 137 |                                 if( js[i].code <= ABS_BRAKE ) | 
|---|
 | 138 |                                 { | 
|---|
 | 139 |                                         int axis = mAxisMap[js[i].code]; | 
|---|
 | 140 |                                         assert( axis < 32 && "Too many axes (Max supported is 32). Report this to OIS forums!" ); | 
|---|
| [1505] | 141 |  | 
|---|
| [8351] | 142 |                                         axisMoved[axis] = true; | 
|---|
 | 143 |  | 
|---|
 | 144 |                                         //check for rescaling: | 
|---|
 | 145 |                                         if( mRanges[axis].min == JoyStick::MIN_AXIS && mRanges[axis].max != JoyStick::MAX_AXIS ) | 
|---|
 | 146 |                                         {       //Scale is perfect | 
|---|
 | 147 |                                                 mState.mAxes[axis].abs = js[i].value; | 
|---|
 | 148 |                                         } | 
|---|
 | 149 |                                         else | 
|---|
 | 150 |                                         {       //Rescale | 
|---|
 | 151 |                                                 float proportion = (float)(js[i].value-mRanges[axis].max)/(float)(mRanges[axis].min-mRanges[axis].max); | 
|---|
 | 152 |                                                 mState.mAxes[axis].abs = (int)(32767.0f - (65535.0f * proportion)); | 
|---|
 | 153 |                                         } | 
|---|
| [1505] | 154 |                                 } | 
|---|
| [8351] | 155 |                                 else if( js[i].code <= ABS_HAT3Y ) //A POV - Max four POVs allowed | 
|---|
| [1505] | 156 |                                 { | 
|---|
| [8351] | 157 |                                         //Normalise the POV to between 0-7 | 
|---|
 | 158 |                                         //Even is X Axis, Odd is Y Axis | 
|---|
 | 159 |                                         unsigned char LinuxPovNumber = js[i].code - 16; | 
|---|
 | 160 |                                         short OIS_POVIndex = POV_MASK[LinuxPovNumber]; | 
|---|
 | 161 |  | 
|---|
 | 162 |                                         //Handle X Axis first (Even) (left right) | 
|---|
 | 163 |                                         if((LinuxPovNumber & 0x0001) == 0) | 
|---|
 | 164 |                                         { | 
|---|
 | 165 |                                                 //Why do this? Because, we use a bit field, and when this axis is east, | 
|---|
 | 166 |                                                 //it can't possibly be west too. So clear out the two X axes, then refil | 
|---|
 | 167 |                                                 //it in with the new direction bit. | 
|---|
 | 168 |                                                 //Clear the East/West Bit Flags first | 
|---|
 | 169 |                                                 mState.mPOV[OIS_POVIndex].direction &= 0x11110011; | 
|---|
 | 170 |                                                 if( js[i].value == -1 ) //Left | 
|---|
 | 171 |                                                         mState.mPOV[OIS_POVIndex].direction |= Pov::West; | 
|---|
 | 172 |                                                 else if( js[i].value == 1 ) //Right | 
|---|
 | 173 |                                                         mState.mPOV[OIS_POVIndex].direction |= Pov::East; | 
|---|
 | 174 |                                         } | 
|---|
 | 175 |                                         //Handle Y Axis (Odd) (up down) | 
|---|
 | 176 |                                         else | 
|---|
 | 177 |                                         { | 
|---|
 | 178 |                                                 //Clear the North/South Bit Flags first | 
|---|
 | 179 |                                                 mState.mPOV[OIS_POVIndex].direction &= 0x11111100; | 
|---|
 | 180 |                                                 if( js[i].value == -1 ) //Up | 
|---|
 | 181 |                                                         mState.mPOV[OIS_POVIndex].direction |= Pov::North; | 
|---|
 | 182 |                                                 else if( js[i].value == 1 ) //Down | 
|---|
 | 183 |                                                         mState.mPOV[OIS_POVIndex].direction |= Pov::South; | 
|---|
 | 184 |                                         } | 
|---|
 | 185 |  | 
|---|
 | 186 |                                         if( mBuffered && mListener ) | 
|---|
 | 187 |                                                 if( mListener->povMoved( JoyStickEvent(this,mState), OIS_POVIndex) == false ) | 
|---|
 | 188 |                                                         return; | 
|---|
| [1505] | 189 |                                 } | 
|---|
| [8351] | 190 |                                 break; | 
|---|
 | 191 |                         } | 
|---|
| [1505] | 192 |  | 
|---|
| [8351] | 193 |                          | 
|---|
 | 194 |                         case EV_REL: //Relative Axes (Do any joystick actually have a relative axis?) | 
|---|
 | 195 |         #ifdef OIS_LINUX_JOY_DEBUG | 
|---|
 | 196 |                                 cout << "\nWarning: Relatives axes not supported yet" << endl; | 
|---|
 | 197 |         #endif | 
|---|
 | 198 |                                 break; | 
|---|
 | 199 |                         default: break; | 
|---|
| [1505] | 200 |                         } | 
|---|
 | 201 |                 } | 
|---|
 | 202 |         } | 
|---|
 | 203 |  | 
|---|
 | 204 |         //All axes and POVs are combined into one movement per pair per captured frame | 
|---|
 | 205 |         if( mBuffered && mListener ) | 
|---|
 | 206 |         { | 
|---|
 | 207 |                 for( int i = 0; i < 32; ++i ) | 
|---|
 | 208 |                         if( axisMoved[i] ) | 
|---|
 | 209 |                                 if( mListener->axisMoved( JoyStickEvent(this,mState), i) == false ) | 
|---|
 | 210 |                                         return; | 
|---|
 | 211 |         } | 
|---|
 | 212 | } | 
|---|
 | 213 |  | 
|---|
 | 214 | //-------------------------------------------------------------------// | 
|---|
 | 215 | void LinuxJoyStick::setBuffered(bool buffered) | 
|---|
 | 216 | { | 
|---|
 | 217 |         if( buffered != mBuffered ) | 
|---|
 | 218 |         { | 
|---|
 | 219 |                 mBuffered = buffered; | 
|---|
 | 220 |                 _initialize(); | 
|---|
 | 221 |         } | 
|---|
 | 222 | } | 
|---|
 | 223 |  | 
|---|
 | 224 | //-------------------------------------------------------------------// | 
|---|
 | 225 | JoyStickInfo LinuxJoyStick::_getJoyInfo() | 
|---|
 | 226 | { | 
|---|
 | 227 |         JoyStickInfo js; | 
|---|
 | 228 |  | 
|---|
 | 229 |         js.devId = mDevID; | 
|---|
 | 230 |         js.joyFileD = mJoyStick; | 
|---|
 | 231 |         js.vendor = mVendor; | 
|---|
 | 232 |         js.axes = (int)mState.mAxes.size(); | 
|---|
 | 233 |         js.buttons = (int)mState.mButtons.size(); | 
|---|
 | 234 |         js.hats = mPOVs; | 
|---|
 | 235 |         js.button_map = mButtonMap; | 
|---|
 | 236 |         js.axis_map = mAxisMap; | 
|---|
 | 237 |         js.axis_range = mRanges; | 
|---|
 | 238 |  | 
|---|
 | 239 |         return js; | 
|---|
 | 240 | } | 
|---|
 | 241 |  | 
|---|
 | 242 | //-------------------------------------------------------------------// | 
|---|
 | 243 | JoyStickInfoList LinuxJoyStick::_scanJoys() | 
|---|
 | 244 | { | 
|---|
 | 245 |         JoyStickInfoList joys; | 
|---|
 | 246 |  | 
|---|
 | 247 |         //Search through all of the event devices.. and identify which ones are joysticks | 
|---|
 | 248 |         //xxx move this to InputManager, as it can also scan all other events | 
|---|
 | 249 |         for(int i = 0; i < 64; ++i ) | 
|---|
 | 250 |         { | 
|---|
| [5695] | 251 |                 stringstream s; | 
|---|
| [1505] | 252 |                 s << "/dev/input/event" << i; | 
|---|
| [5695] | 253 |                 int fd = open( s.str().c_str(), O_RDWR |O_NONBLOCK ); | 
|---|
| [1505] | 254 |                 if(fd == -1) | 
|---|
 | 255 |                         continue; | 
|---|
| [5695] | 256 |  | 
|---|
| [1505] | 257 |         #ifdef OIS_LINUX_JOY_DEBUG | 
|---|
| [5695] | 258 |                   cout << "Opening " << s.str() << "..." << endl; | 
|---|
| [1505] | 259 |         #endif | 
|---|
 | 260 |                 try | 
|---|
 | 261 |                 { | 
|---|
 | 262 |                         JoyStickInfo js; | 
|---|
 | 263 |                         if( EventUtils::isJoyStick(fd, js) ) | 
|---|
 | 264 |                         { | 
|---|
 | 265 |                                 joys.push_back(js); | 
|---|
 | 266 |                 #ifdef OIS_LINUX_JOY_DEBUG | 
|---|
| [5695] | 267 |                   cout << "=> Joystick added to list." << endl; | 
|---|
| [1505] | 268 |                 #endif | 
|---|
 | 269 |                         } | 
|---|
 | 270 |                         else | 
|---|
 | 271 |                         { | 
|---|
 | 272 |                 #ifdef OIS_LINUX_JOY_DEBUG | 
|---|
| [5695] | 273 |                   cout << "=> Not a joystick." << endl; | 
|---|
| [1505] | 274 |                 #endif | 
|---|
 | 275 |                                 close(fd); | 
|---|
 | 276 |                         } | 
|---|
 | 277 |                 } | 
|---|
 | 278 |                 catch(...) | 
|---|
 | 279 |                 { | 
|---|
 | 280 |             #ifdef OIS_LINUX_JOY_DEBUG | 
|---|
| [5695] | 281 |               cout << "Exception caught!!" << endl; | 
|---|
| [1505] | 282 |             #endif | 
|---|
 | 283 |                         close(fd); | 
|---|
 | 284 |                 } | 
|---|
 | 285 |         } | 
|---|
 | 286 |  | 
|---|
 | 287 |         return joys; | 
|---|
 | 288 | } | 
|---|
 | 289 |  | 
|---|
 | 290 | //-------------------------------------------------------------------// | 
|---|
 | 291 | void LinuxJoyStick::_clearJoys(JoyStickInfoList &joys) | 
|---|
 | 292 | { | 
|---|
 | 293 |         for(JoyStickInfoList::iterator i = joys.begin(); i != joys.end(); ++i) | 
|---|
 | 294 |                 close(i->joyFileD); | 
|---|
 | 295 |         joys.clear(); | 
|---|
 | 296 | } | 
|---|
 | 297 |  | 
|---|
 | 298 | //-------------------------------------------------------------------// | 
|---|
 | 299 | Interface* LinuxJoyStick::queryInterface(Interface::IType type) | 
|---|
 | 300 | { | 
|---|
 | 301 |         if( ff_effect && type == Interface::ForceFeedback ) | 
|---|
 | 302 |                 return ff_effect; | 
|---|
 | 303 |  | 
|---|
 | 304 |         return 0; | 
|---|
 | 305 | } | 
|---|