zenilib  0.5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Controllers.cpp
Go to the documentation of this file.
1 /* This file is part of the Zenipex Library (zenilib).
2  * Copyright (C) 2011 Mitchell Keith Bloch (bazald).
3  *
4  * zenilib is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * zenilib is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with zenilib. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <zeni_core.h>
19 
20 #include <cassert>
21 
22 #if defined(_DEBUG) && defined(_WINDOWS)
23 #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
24 #define new DEBUG_NEW
25 #endif
26 
27 #include <Zeni/Singleton.hxx>
28 
29 namespace Zeni {
30 
31  template class Singleton<Controllers>;
32 
33  Controllers * Controllers::create() {
34  return new Controllers;
35  }
36 
37  Singleton<Controllers>::Uninit Controllers::g_uninit;
38  Singleton<Controllers>::Reinit Controllers::g_reinit;
39 
40  Controllers::Controllers() {
41  Core::remove_post_reinit(&g_reinit);
42 
44  Core &cr = get_Core();
45 
47  init();
48 
49  cr.lend_pre_uninit(&g_uninit);
50  cr.lend_post_reinit(&g_reinit);
51  }
52 
53  Controllers::~Controllers() {
54  Core::remove_pre_uninit(&g_uninit);
55 
56  uninit();
57  }
58 
60  return Controllers::get();
61  }
62 
64  return m_joysticks.size();
65  }
66 
68  for(size_t i = 0, iend = m_joysticks.size(); i != iend; ++i) {
69  if(m_joysticks[i] && m_joysticks[i]->joystick_id == id)
70  return Sint32(i);
71  }
72 
73  return -1;
74  }
75 
76  const char * Controllers::get_controller_name(const Sint32 &index) const {
77  assert(index >= 0 && Uint32(index) < m_joysticks.size());
78  return SDL_JoystickName(m_joysticks[index]->joystick);
79  }
80 
82  if(m_joysticks[index]->gamecontroller)
83  return SDL_GameControllerGetAttached(m_joysticks[index]->gamecontroller) == SDL_TRUE;
84  return false;
85  }
86 
88  uninit();
89  init();
90  }
91 
92  void Controllers::enable(const bool &
93 #ifndef ANDROID
94  enable_
95 #endif
96  ) {
97 #ifndef ANDROID
99 #endif
100  }
101 
103  SDL_Joystick * const joystick = SDL_JoystickOpen(index);
104  if(!joystick)
105  return;
106 
107  Joystick_Info * info = new Joystick_Info;
108  info->joystick = joystick;
109  info->joystick_id = SDL_JoystickInstanceID(joystick);
110 
111  for(Joystick_Array::iterator it = m_joysticks.begin(), iend = m_joysticks.end(); ; ++it) {
112  if(it != iend) {
113  if(!*it) {
114  *it = info;
115  break;
116  }
117  }
118  else {
119  m_joysticks.push_back(info);
120  break;
121  }
122  }
123 
124  char szGUID[33];
125  SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(info->joystick), szGUID, sizeof(szGUID));
126 
127  if(SDL_IsGameController(index))
128  info->gamecontroller = SDL_GameControllerOpen(index);
129  if(info->gamecontroller) {
130  char * mapping = SDL_GameControllerMapping(info->gamecontroller);
131  std::cerr << "Loaded game controller " << info->joystick_id << ": " << mapping << std::endl;
132  SDL_free(mapping);
133  }
134  else {
135  std::cerr << "Failed to load game controller (" << szGUID << "): " << SDL_GetError() << std::endl;
136  SDL_ClearError();
137  }
138 
139  if(SDL_JoystickIsHaptic(info->joystick) == 1)
140  info->haptic = SDL_HapticOpenFromJoystick(info->joystick);
141  if(info->haptic) {
142  if(SDL_HapticEffectSupported(info->haptic, &info->haptic_effect) == SDL_TRUE) {
143  info->haptic_effect_id = SDL_HapticNewEffect(info->haptic, &info->haptic_effect);
144  if(SDL_HapticRunEffect(info->haptic, info->haptic_effect_id, 1) == -1) {
145  std::cerr << "Failed to run effect on joystick (" << szGUID << ")." << std::endl;
146  SDL_ClearError();
147  }
148  }
149  }
150  else {
151  std::cerr << "Joystick (" << szGUID << ") not recognized as haptic." << std::endl;
152  SDL_ClearError();
153  }
154  }
155 
157  for(Joystick_Array::iterator it = m_joysticks.begin(), iend = m_joysticks.end(); it != iend; ++it) {
158  if(*it && (*it)->joystick_id == id) {
159  delete *it;
160  *it = 0;
161  break;
162  }
163  }
164  }
165 
167  for(Joystick_Array::reverse_iterator it = m_joysticks.rbegin(), iend = m_joysticks.rend(); it != iend; ++it) {
168  if(*it && SDL_JoystickGetAttached((*it)->joystick) == SDL_FALSE)
169  device_removed((*it)->joystick_id);
170  }
171 
172  //for(int i = SDL_NumJoysticks() - 1; i > -1; --i) {
173  // SDL_Joystick * joystick = SDL_JoystickOpen(i);
174  // Sint32 joystick_id = SDL_JoystickInstanceID(joystick);
175  // SDL_JoystickClose(joystick);
176  // bool found = false;
177  // for(Joystick_Array::reverse_iterator it = m_joysticks.rbegin(), iend = m_joysticks.rend(); it != iend; ++it) {
178  // if((*it) && (*it)->joystick_id == joystick_id) {
179  // found = true;
180  // break;
181  // }
182  // }
183  // if(!found)
184  // device_added(i);
185  //}
186  }
187 
188  void Controllers::device_add_all() {
189  for(int i = 0, iend = SDL_NumJoysticks(); i != iend; ++i)
190  device_added(i);
191  }
192 
193  void Controllers::set_vibration(const size_t &index, const float &left, const float &right) {
194  if(index < m_joysticks.size() && m_joysticks[index]) {
195  m_joysticks[index]->haptic_effect.leftright.large_magnitude = Uint16(left * 0xFFFF);
196  m_joysticks[index]->haptic_effect.leftright.small_magnitude = Uint16(right * 0xFFFF);
197  if(m_joysticks[index]->haptic_effect_id > -1) {
198  if(SDL_HapticUpdateEffect(m_joysticks[index]->haptic, m_joysticks[index]->haptic_effect_id, &m_joysticks[index]->haptic_effect) == -1)
199  SDL_ClearError();
200  }
201  }
202  }
203 
205  for(int i = 0, iend = m_joysticks.size(); i != iend; ++i)
206  set_vibration(i, 0.0f, 0.0f);
207  }
208 
209  Controllers::Joystick_Info::Joystick_Info()
210  : joystick(0),
211  gamecontroller(0),
212  haptic(0),
213  haptic_effect_id(-1)
214  {
215  memset(&haptic_effect, 0, sizeof(haptic_effect));
217  haptic_effect.leftright.length = SDL_HAPTIC_INFINITY;
218  }
219 
220  Controllers::Joystick_Info::~Joystick_Info() {
222  if(haptic) {
223  if(haptic_effect_id > -1)
224  SDL_HapticDestroyEffect(haptic, haptic_effect_id);
225  SDL_HapticClose(haptic);
226  SDL_ClearError();
227  }
228  if(gamecontroller)
229  SDL_GameControllerClose(gamecontroller);
230  SDL_JoystickClose(joystick);
232  }
233 
234  void Controllers::init() {
235 #ifndef ANDROID
237  throw Controllers_Init_Failure();
238 
239  const String appdata_path = get_File_Ops().get_appdata_path();
240  const String user_normal = appdata_path + "config/zenilib.xml";
241  const String local_normal = "config/zenilib.xml";
242  XML_Document file;
243 
244  if(file.try_load(local_normal)) {
245  XML_Element_c zenilib = file["Zenilib"];
246  XML_Element_c joysticks = zenilib["Controllers"];
247  if(joysticks.good()) {
248  for(XML_Element_c joystick = joysticks.first(); joystick.good(); joystick = joystick.next()) {
249  if(joystick.value() == "GameController") {
250  if(SDL_GameControllerAddMapping(joystick.to_string().c_str()) < 0)
251  std::cerr << "Joystick mapping " << joystick.to_string().c_str() << " failed." << std::endl;
252  else
253  std::cerr << "Added/Updating joystick mapping: " << joystick.to_string().c_str() << std::endl;
254  }
255  }
256  }
257  }
258 
259  if(file.try_load(user_normal)) {
260  XML_Element_c zenilib = file["Zenilib"];
261  XML_Element_c joysticks = zenilib["Controllers"];
262  if(joysticks.good()) {
263  for(XML_Element_c joystick = joysticks.first(); joystick.good(); joystick = joystick.next()) {
264  if(joystick.value() == "GameController") {
265  if(SDL_GameControllerAddMapping(joystick.to_string().c_str()) < 0)
266  std::cerr << "Joystick mapping " << joystick.to_string().c_str() << " failed." << std::endl;
267  else
268  std::cerr << "Added/Updating joystick mapping: " << joystick.to_string().c_str() << std::endl;
269  }
270  }
271  }
272  }
273 
274  device_add_all();
275 
278 #endif
279  }
280 
281  void Controllers::uninit() {
282 #ifndef ANDROID
285 
286  for(Joystick_Array::iterator it = m_joysticks.begin(), iend = m_joysticks.end(); it != iend; ++it)
287  delete *it;
288  m_joysticks.clear();
289 
291 
293 #endif
294  }
295 
296 #ifdef ENABLE_XINPUT
297  Controllers::XInputEnable_fcn Controllers::g_XInputEnable = 0;
298  Controllers::XInputGetCapabilities_fcn Controllers::g_XInputGetCapabilities = 0;
299  Controllers::XInputGetState_fcn Controllers::g_XInputGetState = 0;
300  Controllers::XInputSetState_fcn Controllers::g_XInputSetState = 0;
301 #endif
302 
303 }
DECLSPEC void SDLCALL SDL_GameControllerClose(SDL_GameController *gamecontroller)
Controllers & get_Controllers()
Get access to the singleton.
Definition: Controllers.cpp:59
static void assert_no_error()
If there is an SDL error, print it and assert(false)
Definition: Core.cpp:122
int32_t Sint32
A signed 32-bit integer type.
Definition: SDL_stdinc.h:141
DECLSPEC int SDLCALL SDL_HapticUpdateEffect(SDL_Haptic *haptic, int effect, SDL_HapticEffect *data)
Updates the properties of an effect.
Definition: SDL_haptic.c:511
#define SDL_INIT_HAPTIC
Definition: SDL.h:112
GLint left
Definition: glew.h:7291
bool is_controller_connected(const Sint32 &index) const
Check to see if the controller is currently connected.
Definition: Controllers.cpp:81
DECLSPEC SDL_JoystickID SDLCALL SDL_JoystickInstanceID(SDL_Joystick *joystick)
Definition: SDL_joystick.c:372
GLclampf f
Definition: glew.h:3390
#define SDL_INIT_JOYSTICK
Definition: SDL.h:111
DECLSPEC SDL_bool SDLCALL SDL_JoystickGetAttached(SDL_Joystick *joystick)
Definition: SDL_joystick.c:359
DECLSPEC void SDLCALL SDL_JoystickClose(SDL_Joystick *joystick)
Definition: SDL_joystick.c:398
DECLSPEC SDL_GameController *SDLCALL SDL_GameControllerOpen(int joystick_index)
void reset_vibration_all()
Set vibration for all controllers to &lt;0,0&gt;
void detect_removed()
Fix to broken SDL device removal detection.
DECLSPEC SDL_Haptic *SDLCALL SDL_HapticOpenFromJoystick(SDL_Joystick *joystick)
Opens a Haptic device for usage from a Joystick device.
Definition: SDL_haptic.c:272
DECLSPEC void SDLCALL SDL_free(void *mem)
#define memset
Definition: SDL_malloc.c:633
#define SDL_ENABLE
Definition: SDL_events.h:688
FILE * file
Definition: visualinfo.c:88
DECLSPEC void SDLCALL SDL_HapticClose(SDL_Haptic *haptic)
Closes a Haptic device previously opened with SDL_HapticOpen().
Definition: SDL_haptic.c:339
void enable(const bool &enable_)
Temporarily turn controller input on/off.
Definition: Controllers.cpp:92
DECLSPEC int SDLCALL SDL_GameControllerEventState(int state)
#define assert(x)
Definition: SDL_malloc.c:1234
void device_added(const Sint32 &index)
Register a new device.
DECLSPEC const char *SDLCALL SDL_GetError(void)
Definition: SDL_error.c:204
static void remove_post_reinit(Event::Handler *const &handler)
DECLSPEC SDL_bool SDLCALL SDL_IsGameController(int joystick_index)
#define SDL_HAPTIC_INFINITY
Used to play a device an infinite number of times.
Definition: SDL_haptic.h:344
void reinit()
Reload all joysticks, flushing all SDL events and possibly changing &#39;which&#39; values for controllers...
Definition: Controllers.cpp:87
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:145
DECLSPEC int SDLCALL SDL_JoystickIsHaptic(SDL_Joystick *joystick)
Checks to see if a joystick has haptic features.
Definition: SDL_haptic.c:248
DECLSPEC int SDLCALL SDL_HapticEffectSupported(SDL_Haptic *haptic, SDL_HapticEffect *effect)
Checks to see if effect is supported by haptic.
Definition: SDL_haptic.c:446
static void remove_pre_uninit(Event::Handler *const &handler)
Sint32 get_controller_index(const Sint32 &id) const
Get the index of a given controller from the true SDL_JoystickInstanceID.
Definition: Controllers.cpp:67
DECLSPEC int SDLCALL SDL_HapticNewEffect(SDL_Haptic *haptic, SDL_HapticEffect *effect)
Creates a new haptic effect on the device.
Definition: SDL_haptic.c:461
const char * get_controller_name(const Sint32 &index) const
Get the name of a given controller.
Definition: Controllers.cpp:76
DECLSPEC int SDLCALL SDL_InitSubSystem(Uint32 flags)
Definition: SDL.c:103
static Controllers & get()
#define SDL_INIT_GAMECONTROLLER
Definition: SDL.h:113
GLuint index
Definition: glew.h:1800
DECLSPEC char *SDLCALL SDL_GameControllerMapping(SDL_GameController *gamecontroller)
size_t get_num_controllers() const
Get the number of controllers attached to the system.
Definition: Controllers.cpp:63
The Controllers Singleton.
Definition: Controllers.h:50
DECLSPEC int SDLCALL SDL_JoystickEventState(int state)
Definition: SDL_joystick.c:708
DECLSPEC void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
Definition: SDL_joystick.c:770
#define SDL_DISABLE
Definition: SDL_events.h:687
String get_appdata_path()
Get the path that should be used for user-modifiable storage.
Definition: File_Ops.cpp:223
void set_vibration(const size_t &index, const float &left, const float &right)
Set vibration for controller [0,...] to &lt;[0,1],[0,1]&gt;
DECLSPEC const char *SDLCALL SDL_JoystickName(SDL_Joystick *joystick)
Definition: SDL_joystick.c:385
DECLSPEC void SDLCALL SDL_ClearError(void)
Definition: SDL_error.c:212
DECLSPEC SDL_JoystickGUID SDLCALL SDL_JoystickGetGUID(SDL_Joystick *joystick)
Definition: SDL_joystick.c:764
DECLSPEC SDL_bool SDLCALL SDL_GameControllerGetAttached(SDL_GameController *gamecontroller)
Core & get_Core()
Get access to the singleton.
Definition: Core.cpp:71
DECLSPEC void SDLCALL SDL_HapticDestroyEffect(SDL_Haptic *haptic, int effect)
Destroys a haptic effect on the device.
Definition: SDL_haptic.c:576
DECLSPEC SDL_Joystick *SDLCALL SDL_JoystickOpen(int device_index)
Definition: SDL_joystick.c:101
GLenum GLenum GLenum GLenum mapping
Definition: glew.h:12631
DECLSPEC int SDLCALL SDL_HapticRunEffect(SDL_Haptic *haptic, int effect, Uint32 iterations)
Runs the haptic effect on its associated haptic device.
Definition: SDL_haptic.c:539
DECLSPEC int SDLCALL SDL_GameControllerAddMapping(const char *mappingString)
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:137
int i
Definition: pngrutil.c:1377
GLfloat right
Definition: glew.h:13816
File_Ops & get_File_Ops()
Get access to the singleton.
Definition: File_Ops.cpp:118
#define SDL_HAPTIC_LEFTRIGHT
Left/Right effect supported.
Definition: SDL_haptic.h:177
void device_removed(const Sint32 &id)
Remove a device.
DECLSPEC void SDLCALL SDL_QuitSubSystem(Uint32 flags)
Definition: SDL.c:241
DECLSPEC int SDLCALL SDL_NumJoysticks(void)
Definition: SDL_joystick.c:75