FIFE  6e1afdbeda11afe9ac53e6023a4be96ef88f1dc6
joystickmanager.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2017 by the FIFE team *
3  * http://www.fifengine.net *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <iostream>
24 
25 // 3rd party library includes
26 #include <SDL.h>
27 
28 // FIFE includes
29 // These includes are split up in two parts, separated by one empty line
30 // First block: files included from the FIFE root src directory
31 // Second block: files included from the same folder
32 //#include "loaders/native/input/controllermappingloader.h"
33 //#include "savers/native/input/controllermappingsaver.h"
34 #include "util/base/exception.h"
35 #include "util/log/logger.h"
36 #include "util/math/fife_math.h"
37 
38 #include "joystickmanager.h"
39 
40 namespace FIFE {
41  static Logger _log(LM_EVTCHANNEL);
42 
44  // init joystick and controller systems
45  if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) {
46  throw SDLException(SDL_GetError());
47  }
48  // create loader/saver for controller mappings
51 
52  // add already connected joysticks / controllers
53  for (int32_t i = 0; i < SDL_NumJoysticks(); ++i) {
54  addJoystick(i);
55  }
56  // enable joystick and gamecontroller events
57  SDL_JoystickEventState(SDL_ENABLE);
58  SDL_GameControllerEventState(SDL_ENABLE);
59  }
60 
62  for (std::vector<Joystick*>::iterator it = m_joysticks.begin(); it != m_joysticks.end(); ++it) {
63  delete *it;
64  }
65 
66  SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
67  }
68 
69  Joystick* JoystickManager::addJoystick(int32_t deviceIndex) {
70  Joystick* joystick = NULL;
71  for (std::vector<Joystick*>::iterator it = m_activeJoysticks.begin(); it != m_activeJoysticks.end(); ++it) {
72  if ((*it)->getDeviceIndex() == deviceIndex) {
73  return joystick;
74  }
75  }
76  std::string guidStr = getGuidString(deviceIndex);
77  for (std::vector<Joystick*>::iterator it = m_joysticks.begin(); it != m_joysticks.end(); ++it) {
78  if (!(*it)->isConnected() && (*it)->getGuid() == guidStr) {
79  joystick = *it;
80  break;
81  }
82  }
83  if (!joystick) {
84  joystick = new Joystick(m_joysticks.size(), deviceIndex);
85  m_joysticks.push_back(joystick);
86  } else {
87  joystick->setDeviceIndex(deviceIndex);
88  }
89  joystick->open();
90  addControllerGuid(joystick);
91  m_joystickIndices.insert(std::pair<int32_t, uint32_t>(joystick->getInstanceId(), joystick->getJoystickId()));
92  m_activeJoysticks.push_back(joystick);
93  return joystick;
94  }
95 
96  Joystick* JoystickManager::getJoystick(int32_t instanceId) {
97  Joystick* joy = NULL;
98  std::map<int32_t, uint32_t>::iterator it = m_joystickIndices.find(instanceId);
99  if (it != m_joystickIndices.end()) {
100  joy = m_joysticks[it->second];
101  }
102  return joy;
103  }
104 
106  std::vector<Joystick*>::iterator it = std::find(m_activeJoysticks.begin(), m_activeJoysticks.end(), joystick);
107  if (it != m_activeJoysticks.end()) {
108  m_joystickIndices.erase((*it)->getInstanceId());
110  (*it)->close();
111  m_activeJoysticks.erase(it);
112  }
113  }
114 
116  return static_cast<uint8_t>(m_activeJoysticks.size());
117  }
118 
119  void JoystickManager::loadMapping(const std::string& file) {
120  m_mappingLoader.load(file);
121  // check if one of the joysticks can now be opened as gamecontroller
122  for (std::vector<Joystick*>::iterator it = m_activeJoysticks.begin(); it != m_activeJoysticks.end(); ++it) {
123  if (!(*it)->isController()) {
124  (*it)->openController();
125  addControllerGuid(*it);
126  }
127  }
128  }
129 
130  void JoystickManager::saveMapping(const std::string guid, const std::string& file) {
131  std::string stringMapping = getStringMapping(guid);
132  m_mappingSaver.save(stringMapping, file);
133  }
134 
135  void JoystickManager::saveMappings(const std::string& file) {
136  std::string stringMappings;
137  std::map<std::string, uint8_t>::iterator it = m_gamepadGuids.begin();
138  for (; it != m_gamepadGuids.end(); ++it) {
139  stringMappings += getStringMapping(it->first);
140  }
141  m_mappingSaver.save(stringMappings, file);
142  }
143 
144  std::string JoystickManager::getStringMapping(const std::string& guid) {
145  SDL_JoystickGUID realGuid = SDL_JoystickGetGUIDFromString(guid.c_str());
146  char* mapping = SDL_GameControllerMappingForGUID(realGuid);
147  if (!mapping) {
148  throw SDLException(SDL_GetError());
149  return std::string();
150  }
151 
152  std::string stringMapping(mapping);
153  SDL_free(mapping);
154  // add missing platform if needed
155  if (stringMapping.find_last_of(',') != stringMapping.length() - 1) {
156  stringMapping += ",";
157  }
158  std::size_t platPos = stringMapping.find("platform:");
159  if (platPos == std::string::npos) {
160  stringMapping += "platform:" + std::string(SDL_GetPlatform()) + ",\n";
161  }
162  return stringMapping;
163  }
164 
165  void JoystickManager::setStringMapping(const std::string& mapping) {
166  int32_t result = SDL_GameControllerAddMapping(mapping.c_str());
167  if (result == 1) {
168  // check if one of the joysticks can now be opened as gamecontroller
169  for (std::vector<Joystick*>::iterator it = m_activeJoysticks.begin(); it != m_activeJoysticks.end(); ++it) {
170  if (!(*it)->isController()) {
171  (*it)->openController();
172  addControllerGuid(*it);
173  }
174  }
175  } else if (result == -1) {
176  throw SDLException(SDL_GetError());
177  }
178  }
179 
181  m_pendingJoystickListeners.push_back(listener);
182  }
183 
185  m_pendingJoystickListenersFront.push_back(listener);
186  }
187 
189  m_pendingJoystickListenersFront.push_back(listener);
190  }
191 
193  bool dispatch = true;
194  JoystickEvent joyevt;
195  joyevt.setSource(this);
196 
197  if (event.type == SDL_JOYAXISMOTION) {
199  joyevt.setInstanceId(event.jaxis.which);
200  joyevt.setAxis(event.jaxis.axis);
201  joyevt.setAxisValue(convertRange(event.jaxis.value));
202  } else if (event.type == SDL_JOYBUTTONDOWN || event.type == SDL_JOYBUTTONUP) {
203  joyevt.setType(event.type == SDL_JOYBUTTONDOWN ? JoystickEvent::BUTTON_PRESSED : JoystickEvent::BUTTON_RELEASED);
204  joyevt.setInstanceId(event.jbutton.which);
205  joyevt.setButton(event.jbutton.button);
206  } else if (event.type == SDL_JOYHATMOTION) {
208  joyevt.setInstanceId(event.jhat.which);
209  joyevt.setHat(event.jhat.hat);
210  joyevt.setHatValue(event.jhat.value);
211  } else if (event.type == SDL_JOYDEVICEADDED) {
213  // Note: In this case it's the device index, instead of instance id
214  Joystick* joy = addJoystick(event.jdevice.which);
215  if (joy) {
216  joyevt.setInstanceId(joy->getInstanceId());
217  } else {
218  dispatch = false;
219  }
220  } else if (event.type == SDL_JOYDEVICEREMOVED) {
222  joyevt.setInstanceId(event.jdevice.which);
223  } else {
224  dispatch = false;
225  }
226  // Dispatch only if it's not a controller, SDL sends events twice.
227  // Only exception for added and removed events.
228  Joystick* joy = getJoystick(joyevt.getInstanceId());
229  dispatch = dispatch && (!joy->isController() || (event.type == SDL_JOYDEVICEREMOVED || event.type == SDL_JOYDEVICEADDED));
230  if (dispatch) {
231  joyevt.setController(joy->isController());
232  dispatchJoystickEvent(joyevt);
233  }
234  // Remove it after event dispatch.
235  if (event.type == SDL_JOYDEVICEREMOVED) {
236  removeJoystick(joy);
237  }
238  }
239 
241  bool dispatch = true;
242  JoystickEvent joyevt;
243  joyevt.setSource(this);
244  joyevt.setController(true);
245 
246  if (event.type == SDL_CONTROLLERAXISMOTION) {
248  joyevt.setInstanceId(event.caxis.which);
249  joyevt.setAxis(event.caxis.axis);
250  joyevt.setAxisValue(convertRange(event.caxis.value));
251  } else if (event.type == SDL_CONTROLLERBUTTONDOWN || event.type == SDL_CONTROLLERBUTTONUP) {
252  joyevt.setType(event.type == SDL_CONTROLLERBUTTONDOWN ? JoystickEvent::BUTTON_PRESSED : JoystickEvent::BUTTON_RELEASED);
253  joyevt.setInstanceId(event.cbutton.which);
254  joyevt.setButton(event.cbutton.button);
255  } else {
256  dispatch = false;
257  }
258 
259  if (dispatch) {
260  dispatchJoystickEvent(joyevt);
261  }
262  }
263 
264 
266  if (!m_pendingJoystickListeners.empty()) {
267  std::deque<IJoystickListener*>::iterator i = m_pendingJoystickListeners.begin();
268  while (i != m_pendingJoystickListeners.end()) {
269  m_joystickListeners.push_back(*i);
270  ++i;
271  }
273  }
274 
275  if (!m_pendingJoystickListenersFront.empty()) {
276  std::deque<IJoystickListener*>::iterator i = m_pendingJoystickListenersFront.begin();
277  while (i != m_pendingJoystickListenersFront.end()) {
278  m_joystickListeners.push_front(*i);
279  ++i;
280  }
282  }
283 
284  if (!m_pendingJoystickDeletions.empty()) {
285  std::deque<IJoystickListener*>::iterator i = m_pendingJoystickDeletions.begin();
286  while (i != m_pendingJoystickDeletions.end()) {
287  std::deque<IJoystickListener*>::iterator j = m_joystickListeners.begin();
288  while (j != m_joystickListeners.end()) {
289  if (*j == *i) {
290  m_joystickListeners.erase(j);
291  break;
292  }
293  ++j;
294  }
295  ++i;
296  }
298  }
299 
300  std::deque<IJoystickListener*>::iterator i = m_joystickListeners.begin();
301  while (i != m_joystickListeners.end()) {
302  switch (evt.getType()) {
304  (*i)->axisMotion(evt);
305  break;
307  (*i)->hatMotion(evt);
308  break;
310  (*i)->buttonPressed(evt);
311  break;
313  (*i)->buttonReleased(evt);
314  break;
316  (*i)->deviceAdded(evt);
317  break;
319  (*i)->deviceRemoved(evt);
320  break;
321  default:
322  break;
323  }
324  ++i;
325  }
326  }
327 
329  return ES_ENGINE;
330  }
331 
332  std::string JoystickManager::getGuidString(int32_t deviceIndex) {
333  char tmp[33];
334  SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(deviceIndex);
335  SDL_JoystickGetGUIDString(guid, tmp, sizeof(tmp));
336  std::string guidString(tmp);
337  return guidString;
338  }
339 
340  float JoystickManager::convertRange(int16_t value) {
341  float range = static_cast<float>(value) / 32768.0f;
342  if (Mathf::FAbs(range) < 0.01f) {
343  return 0.0f;
344  }
345  if (range < -0.99f) {
346  return -1.0f;
347  } else if (range > 0.99f) {
348  return 1.0f;
349  }
350  return range;
351  }
352 
354  if (!joystick->isController()) {
355  return;
356  }
357  std::pair<std::map<std::string, uint8_t>::iterator, bool> ret;
358  ret = m_gamepadGuids.insert(std::pair<std::string, uint8_t>(joystick->getGuid(), 1));
359  if (ret.second == false) {
360  ++ret.first->second;
361  }
362  }
363 
365  if (!joystick->isController()) {
366  return;
367  }
368  std::map<std::string, uint8_t>::iterator it = m_gamepadGuids.find(joystick->getGuid());
369  if (it != m_gamepadGuids.end()) {
370  --it->second;
371  }
372  }
373 }
void addJoystickListener(IJoystickListener *listener)
Adds a listener to the back of the listener deque Listener will be notified via the corresponding eve...
JoystickManager()
Constructor.
void save(const std::string data, const std::string &filename)
Saves mapping to file.
virtual ~JoystickManager()
Destructor.
void removeJoystick(Joystick *joystick)
Removes the given joystick, can be reused.
void processJoystickEvent(SDL_Event event)
Creates and process joystick events.
ControllerMappingLoader m_mappingLoader
Loader for gamecontroller mapping.
bool isController() const
Indicates if this a controller.
Definition: joystick.cpp:119
float convertRange(int16_t value)
Converts the int16 in -1.0 to 1.0 range.
void removeControllerGuid(Joystick *joystick)
Removes / decal controller GUID.
static Logger _log(LM_AUDIO)
int32_t getJoystickId() const
Sets the instance id of the joystick.
Definition: joystick.cpp:60
std::map< std::string, uint8_t > m_gamepadGuids
Each sort of gamepad have a GUID from SDL. Indicates the number of gamepads with given GUID are conne...
void setStringMapping(const std::string &mapping)
Sets controller mapping from string and adds or updates the related controllers.
void setHat(int8_t hat)
Sets the hat index.
std::vector< Joystick * > m_joysticks
All "known" Joysticks. Useful if a user reconnect a Joystick.
int32_t getInstanceId() const
Return the instance id of the joystick.
Definition: joystick.cpp:56
void setAxis(int8_t axis)
Sets the axis index number or the Joystick::ControllerAxis.
Definition: joystickevent.h:96
void setDeviceIndex(int32_t deviceIndex)
Sets the device index of the joystick.
Definition: joystick.cpp:64
Listener of joystick events.
JoystickEventType getType() const
Return the event type.
Definition: joystickevent.h:76
std::deque< IJoystickListener * > m_pendingJoystickDeletions
std::vector< Joystick * > m_activeJoysticks
All active / connected Joysticks.
Represents a Joystick and if available the Gamecontroller.
Definition: joystick.h:39
unsigned char uint8_t
Definition: core.h:38
void addControllerGuid(Joystick *joystick)
Adds GUID from controller.
std::map< int32_t, uint32_t > m_joystickIndices
void setType(JoystickEventType type)
Sets the event type.
Definition: joystickevent.h:80
void dispatchJoystickEvent(JoystickEvent &evt)
Dispatches joystick / controller events.
void setInstanceId(int32_t id)
Sets the instance id of the joystick.
Definition: joystickevent.h:88
const std::string & getGuid()
Return the GUID of the joystick / gamecontroller class as string.
Definition: joystick.cpp:72
ControllerMappingSaver m_mappingSaver
Saver for gamecontroller mapping.
std::deque< IJoystickListener * > m_pendingJoystickListeners
void load(const std::string &filename)
Loads mapping from file.
void setController(bool value)
Sets to true if the event is for a controller, otherwise false.
void saveMapping(const std::string guid, const std::string &file)
Saves controller mapping for given GUID in the specified file.
uint8_t getJoystickCount() const
Return the number of joysticks / gamecontrollers.
void processControllerEvent(SDL_Event event)
Creates and process gamecontroller events.
std::string getGuidString(int32_t deviceIndex)
Return GUID for given device index as string.
Joystick * getJoystick(int32_t instanceId)
Return the joystick with the given instance id.
void loadMapping(const std::string &file)
Loads controller mappings from given file and if possible, it opens the related controllers.
void addJoystickListenerFront(IJoystickListener *listener)
Adds a listener to the front of the listener deque Listener will be notified via the corresponding ev...
Class for Joystick events.
Definition: joystickevent.h:45
std::string getStringMapping(const std::string &guid)
Return the controller mapping for given GUID as string.
void removeJoystickListener(IJoystickListener *listener)
Removes an added listener from the controller.
Joystick * addJoystick(int32_t deviceIndex)
Adds a joystick with the given device index.
void setButton(int8_t button)
Sets the button index or Joystick::ControllerButton.
int32_t getInstanceId() const
Return the instance id of the joystick.
Definition: joystickevent.h:84
void saveMappings(const std::string &file)
Saves all controller mappings that were used during the season.
EventSourceType
Types for different event sources.
void setHatValue(int8_t value)
Sets the hat value.
void setAxisValue(float value)
Sets the axis value.
static T FAbs(T _val)
Definition: fife_math.h:227
void open()
Opens / activates the joystick and sets values.
Definition: joystick.cpp:80
virtual void setSource(IEventSource *source)
Sets the source of the event.
std::deque< IJoystickListener * > m_joystickListeners
EventSourceType getEventSourceType()
Gets the source type of this event.
std::deque< IJoystickListener * > m_pendingJoystickListenersFront