1 /* ------------------------------------------------------- 2 Copyright (c) 2011 Alberto G. Salguero (alberto.salguero (at) uca.es) 3 4 Permission is hereby granted, free of charge, to any 5 person obtaining a copy of this software and associated 6 documentation files (the "Software"), to deal in the 7 Software without restriction, including without limitation 8 the rights to use, copy, modify, merge, publish, 9 distribute, sublicense, and/or sell copies of the 10 Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice 14 shall be included in all copies or substantial portions of 15 the Software. 16 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 18 KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 19 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 20 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 21 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 ------------------------------------------------------- */ 26 27 #include "ICSInputControlSystem.h" 28 29 #define SDL_JOY_AXIS_MIN -32768 30 #define SDL_JOY_AXIS_MAX 32767 31 32 namespace ICS 33 { 34 // load xml loadJoystickAxisBinders(TiXmlElement * xmlControlNode)35 void InputControlSystem::loadJoystickAxisBinders(TiXmlElement* xmlControlNode) 36 { 37 TiXmlElement* xmlJoystickBinder = xmlControlNode->FirstChildElement("JoystickAxisBinder"); 38 while(xmlJoystickBinder) 39 { 40 Control::ControlChangingDirection dir = Control::STOP; 41 if(std::string(xmlJoystickBinder->Attribute("direction")) == "INCREASE") 42 { 43 dir = Control::INCREASE; 44 } 45 else if(std::string(xmlJoystickBinder->Attribute("direction")) == "DECREASE") 46 { 47 dir = Control::DECREASE; 48 } 49 50 addJoystickAxisBinding(mControls.back(), FromString<int>(xmlJoystickBinder->Attribute("deviceId")), FromString<int>(xmlJoystickBinder->Attribute("axis")), dir); 51 52 xmlJoystickBinder = xmlJoystickBinder->NextSiblingElement("JoystickAxisBinder"); 53 } 54 } 55 loadJoystickButtonBinders(TiXmlElement * xmlControlNode)56 void InputControlSystem::loadJoystickButtonBinders(TiXmlElement* xmlControlNode) 57 { 58 TiXmlElement* xmlJoystickButtonBinder = xmlControlNode->FirstChildElement("JoystickButtonBinder"); 59 while(xmlJoystickButtonBinder) 60 { 61 Control::ControlChangingDirection dir = Control::STOP; 62 if(std::string(xmlJoystickButtonBinder->Attribute("direction")) == "INCREASE") 63 { 64 dir = Control::INCREASE; 65 } 66 else if(std::string(xmlJoystickButtonBinder->Attribute("direction")) == "DECREASE") 67 { 68 dir = Control::DECREASE; 69 } 70 71 addJoystickButtonBinding(mControls.back(), FromString<int>(xmlJoystickButtonBinder->Attribute("deviceId")), FromString<int>(xmlJoystickButtonBinder->Attribute("button")), dir); 72 73 xmlJoystickButtonBinder = xmlJoystickButtonBinder->NextSiblingElement("JoystickButtonBinder"); 74 } 75 } 76 77 // add bindings addJoystickAxisBinding(Control * control,int deviceID,int axis,Control::ControlChangingDirection direction)78 void InputControlSystem::addJoystickAxisBinding(Control* control, int deviceID, int axis, Control::ControlChangingDirection direction) 79 { 80 if (std::find(mJoystickIDList.begin(), mJoystickIDList.end(), deviceID) == mJoystickIDList.end()) 81 mJoystickIDList.push_back(deviceID); 82 83 ICS_LOG("\tAdding AxisBinder [axis=" 84 + ToString<int>(axis) + ", deviceID=" 85 + ToString<int>(deviceID) + ", direction=" 86 + ToString<int>(direction) + "]"); 87 88 control->setValue(0.5f); //all joystick axis start at .5, so do that 89 90 ControlAxisBinderItem controlAxisBinderItem; 91 controlAxisBinderItem.control = control; 92 controlAxisBinderItem.direction = direction; 93 mControlsJoystickAxisBinderMap[deviceID][axis] = controlAxisBinderItem; 94 } 95 addJoystickButtonBinding(Control * control,int deviceID,unsigned int button,Control::ControlChangingDirection direction)96 void InputControlSystem::addJoystickButtonBinding(Control* control, int deviceID, unsigned int button, Control::ControlChangingDirection direction) 97 { 98 if (std::find(mJoystickIDList.begin(), mJoystickIDList.end(), deviceID) == mJoystickIDList.end()) 99 mJoystickIDList.push_back(deviceID); // Hack: add the device to the list so bindings are saved in save() even when joystick is not connected 100 101 ICS_LOG("\tAdding JoystickButtonBinder [button=" 102 + ToString<int>(button) + ", deviceID=" 103 + ToString<int>(deviceID) + ", direction=" 104 + ToString<int>(direction) + "]"); 105 106 ControlButtonBinderItem controlJoystickButtonBinderItem; 107 controlJoystickButtonBinderItem.direction = direction; 108 controlJoystickButtonBinderItem.control = control; 109 mControlsJoystickButtonBinderMap[deviceID][button] = controlJoystickButtonBinderItem; 110 } 111 isJoystickButtonBound(int deviceID,unsigned int button) const112 bool InputControlSystem::isJoystickButtonBound(int deviceID, unsigned int button) const 113 { 114 JoystickButtonBinderMapType::const_iterator found = mControlsJoystickButtonBinderMap.find(deviceID); 115 if (found == mControlsJoystickButtonBinderMap.end()) 116 return false; 117 118 return (found->second.find(button) != found->second.end()); 119 } 120 isJoystickAxisBound(int deviceID,unsigned int axis) const121 bool InputControlSystem::isJoystickAxisBound(int deviceID, unsigned int axis) const 122 { 123 JoystickAxisBinderMapType::const_iterator found = mControlsJoystickAxisBinderMap.find(deviceID); 124 if (found == mControlsJoystickAxisBinderMap.end()) 125 return false; 126 127 return (found->second.find(axis) != found->second.end()); 128 } 129 130 // get bindings getJoystickAxisBinding(Control * control,int deviceID,ICS::Control::ControlChangingDirection direction)131 int InputControlSystem::getJoystickAxisBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) 132 { 133 if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) 134 { 135 ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].begin(); 136 while(it != mControlsJoystickAxisBinderMap[deviceID].end()) 137 { 138 if(it->first >= 0 && it->second.control == control && it->second.direction == direction) 139 { 140 return it->first; 141 } 142 ++it; 143 } 144 } 145 146 return /*NamedAxis::*/UNASSIGNED; 147 } 148 getJoystickButtonBinding(Control * control,int deviceID,ICS::Control::ControlChangingDirection direction)149 unsigned int InputControlSystem::getJoystickButtonBinding(Control* control, int deviceID, ICS::Control::ControlChangingDirection direction) 150 { 151 if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) 152 { 153 ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].begin(); 154 while(it != mControlsJoystickButtonBinderMap[deviceID].end()) 155 { 156 if(it->second.control == control && it->second.direction == direction) 157 { 158 return it->first; 159 } 160 ++it; 161 } 162 } 163 164 return ICS_MAX_DEVICE_BUTTONS; 165 } 166 167 // remove bindings removeJoystickAxisBinding(int deviceID,int axis)168 void InputControlSystem::removeJoystickAxisBinding(int deviceID, int axis) 169 { 170 if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) 171 { 172 ControlsAxisBinderMapType::iterator it = mControlsJoystickAxisBinderMap[deviceID].find(axis); 173 if(it != mControlsJoystickAxisBinderMap[deviceID].end()) 174 { 175 mControlsJoystickAxisBinderMap[deviceID].erase(it); 176 } 177 } 178 } 179 removeJoystickButtonBinding(int deviceID,unsigned int button)180 void InputControlSystem::removeJoystickButtonBinding(int deviceID, unsigned int button) 181 { 182 if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) 183 { 184 ControlsButtonBinderMapType::iterator it = mControlsJoystickButtonBinderMap[deviceID].find(button); 185 if(it != mControlsJoystickButtonBinderMap[deviceID].end()) 186 { 187 mControlsJoystickButtonBinderMap[deviceID].erase(it); 188 } 189 } 190 } 191 192 // joyStick listeners buttonPressed(int deviceID,const SDL_ControllerButtonEvent & evt)193 void InputControlSystem::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &evt) 194 { 195 if(mActive) 196 { 197 if(!mDetectingBindingControl) 198 { 199 if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) 200 { 201 ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); 202 if(it != mControlsJoystickButtonBinderMap[deviceID].end()) 203 { 204 it->second.control->setIgnoreAutoReverse(false); 205 if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) 206 { 207 it->second.control->setChangingDirection(it->second.direction); 208 } 209 else 210 { 211 if(it->second.control->getValue() == 1) 212 { 213 it->second.control->setChangingDirection(Control::DECREASE); 214 } 215 else if(it->second.control->getValue() == 0) 216 { 217 it->second.control->setChangingDirection(Control::INCREASE); 218 } 219 } 220 } 221 } 222 } 223 } 224 } 225 buttonReleased(int deviceID,const SDL_ControllerButtonEvent & evt)226 void InputControlSystem::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &evt) 227 { 228 if(mActive) 229 { 230 if(!mDetectingBindingControl) 231 { 232 if(mControlsJoystickButtonBinderMap.find(deviceID) != mControlsJoystickButtonBinderMap.end()) 233 { 234 ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[deviceID].find(evt.button); 235 if(it != mControlsJoystickButtonBinderMap[deviceID].end()) 236 { 237 it->second.control->setChangingDirection(Control::STOP); 238 } 239 } 240 } 241 else if(mDetectingBindingListener) 242 { 243 mDetectingBindingListener->joystickButtonBindingDetected(this, deviceID, 244 mDetectingBindingControl, evt.button, mDetectingBindingDirection); 245 } 246 } 247 } 248 axisMoved(int deviceID,const SDL_ControllerAxisEvent & evt)249 void InputControlSystem::axisMoved(int deviceID, const SDL_ControllerAxisEvent &evt) 250 { 251 if(mActive) 252 { 253 if(!mDetectingBindingControl) 254 { 255 if(mControlsJoystickAxisBinderMap.find(deviceID) != mControlsJoystickAxisBinderMap.end()) 256 { 257 ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[deviceID][evt.axis]; // joystic axis start at 0 index 258 Control* ctrl = joystickBinderItem.control; 259 if(ctrl) 260 { 261 ctrl->setIgnoreAutoReverse(true); 262 263 float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MIN; 264 float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); 265 float percent = valDisplaced / axisRange * (1+mDeadZone*2) - mDeadZone; //Assures all values, 0 through 1, are seen 266 if(percent > .5-mDeadZone && percent < .5+mDeadZone) //close enough to center 267 percent = .5; 268 else if(percent > .5) 269 percent -= mDeadZone; 270 else 271 percent += mDeadZone; 272 273 if(joystickBinderItem.direction == Control::INCREASE) 274 { 275 ctrl->setValue( percent ); 276 } 277 else if(joystickBinderItem.direction == Control::DECREASE) 278 { 279 ctrl->setValue( 1 - ( percent ) ); 280 } 281 } 282 } 283 } 284 else if(mDetectingBindingListener) 285 { 286 //ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.which ][ axis ]; // joystic axis start at 0 index 287 //Control* ctrl = joystickBinderItem.control; 288 //if(ctrl && ctrl->isAxisBindable()) 289 if(mDetectingBindingControl->isAxisBindable()) 290 { 291 if( abs( evt.value ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) 292 { 293 mDetectingBindingListener->joystickAxisBindingDetected(this, deviceID, 294 mDetectingBindingControl, evt.axis, mDetectingBindingDirection); 295 } 296 } 297 } 298 } 299 } 300 controllerAdded(int deviceID,const SDL_ControllerDeviceEvent & args)301 void InputControlSystem::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &args) 302 { 303 ICS_LOG("Adding joystick (index: " + ToString<int>(args.which) + ")"); 304 SDL_GameController* cntrl = SDL_GameControllerOpen(args.which); 305 int instanceID = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(cntrl)); 306 if(std::find(mJoystickIDList.begin(), mJoystickIDList.end(), deviceID)==mJoystickIDList.end()) 307 { 308 for(int j = 0 ; j < ICS_MAX_JOYSTICK_AXIS ; j++) 309 { 310 if(mControlsJoystickAxisBinderMap[deviceID].find(j) == mControlsJoystickAxisBinderMap[deviceID].end()) 311 { 312 ControlAxisBinderItem controlJoystickBinderItem; 313 controlJoystickBinderItem.direction = Control::STOP; 314 controlJoystickBinderItem.control = NULL; 315 mControlsJoystickAxisBinderMap[deviceID][j] = controlJoystickBinderItem; 316 } 317 } 318 mJoystickIDList.push_front(deviceID); 319 } 320 321 mJoystickInstanceMap[instanceID] = cntrl; 322 } controllerRemoved(const SDL_ControllerDeviceEvent & args)323 void InputControlSystem::controllerRemoved(const SDL_ControllerDeviceEvent &args) 324 { 325 ICS_LOG("Removing joystick (instance id: " + ToString<int>(args.which) + ")"); 326 if(mJoystickInstanceMap.count(args.which)!=0) 327 { 328 SDL_GameControllerClose(mJoystickInstanceMap.at(args.which)); 329 mJoystickInstanceMap.erase(args.which); 330 } 331 } 332 333 // joystick auto bindings joystickAxisBindingDetected(InputControlSystem * ICS,int deviceID,Control * control,int axis,Control::ControlChangingDirection direction)334 void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, int deviceID, Control* control, int axis, Control::ControlChangingDirection direction) 335 { 336 // if the joystick axis is used by another control, remove it 337 ICS->removeJoystickAxisBinding(deviceID, axis); 338 339 // if the control has an axis assigned, remove it 340 int oldAxis = ICS->getJoystickAxisBinding(control, deviceID, direction); 341 if(oldAxis != InputControlSystem::UNASSIGNED) 342 { 343 ICS->removeJoystickAxisBinding(deviceID, oldAxis); 344 } 345 346 ICS->addJoystickAxisBinding(control, deviceID, axis, direction); 347 ICS->cancelDetectingBindingState(); 348 } joystickButtonBindingDetected(InputControlSystem * ICS,int deviceID,Control * control,unsigned int button,Control::ControlChangingDirection direction)349 void DetectingBindingListener::joystickButtonBindingDetected(InputControlSystem* ICS, int deviceID, Control* control 350 , unsigned int button, Control::ControlChangingDirection direction) 351 { 352 // if the joystick button is used by another control, remove it 353 ICS->removeJoystickButtonBinding(deviceID, button); 354 355 // if the control has a joystick button assigned, remove it 356 unsigned int oldButton = ICS->getJoystickButtonBinding(control, deviceID, direction); 357 if(oldButton != ICS_MAX_DEVICE_BUTTONS) 358 { 359 ICS->removeJoystickButtonBinding(deviceID, oldButton); 360 } 361 362 ICS->addJoystickButtonBinding(control, deviceID, button, direction); 363 ICS->cancelDetectingBindingState(); 364 } 365 } 366