]> Shamusworld >> Repos - virtualjaguar/blob - src/gui/gamepad.cpp
873e3b5ad9a81d2efc0f3f7c186a256336fa2d22
[virtualjaguar] / src / gui / gamepad.cpp
1 //
2 // gamepad.cpp - Host joystick handling (using SDL)
3 //
4 // by James Hammons
5 // (C) 2013 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // Who  When        What
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  01/05/2013  Created this file
12 //
13
14 #include "gamepad.h"
15 #include "log.h"
16
17
18 // Class member initialization
19 /*static*/ int Gamepad::numJoysticks = 0;
20 /*static*/ SDL_Joystick * Gamepad::pad[8];
21 /*static*/ char Gamepad::padName[8][128];
22 /*static*/ int Gamepad::numButtons[8];
23 /*static*/ int Gamepad::numHats[8];
24 /*static*/ int Gamepad::numAxes[8];
25 /*static*/ bool Gamepad::button[8][256];
26 /*static*/ uint8_t Gamepad::hat[8][32];
27 /*static*/ int32_t Gamepad::axis[8][32];
28
29
30 Gamepad::Gamepad(void)//: numJoysticks(0)
31 {
32         AllocateJoysticks();
33 }
34
35
36 Gamepad::~Gamepad(void)
37 {
38         DeallocateJoysticks();
39 }
40
41
42 void Gamepad::AllocateJoysticks(void)
43 {
44 //      DeallocateJoysticks();
45         numJoysticks = SDL_NumJoysticks();
46
47         // Sanity check
48         if (numJoysticks > 8)
49                 numJoysticks = 8;
50
51         for(int i=0; i<numJoysticks; i++)
52         {
53                 pad[i] = SDL_JoystickOpen(i);
54                 numButtons[i] = numHats[i] = numAxes[i] = 0;
55                 // We need to copy the contents of this pointer, as SDL will change it
56                 // willy nilly to suit itself
57 //              padName[i] = SDL_JoystickName(i);
58                 strncpy(padName[i], SDL_JoystickName(i), 127);
59                 padName[i][127] = 0;    // Just in case name's length > 127
60
61                 if (pad[i])
62                 {
63                         numButtons[i] = SDL_JoystickNumButtons(pad[i]);
64                         numHats[i] = SDL_JoystickNumHats(pad[i]);
65                         numAxes[i] = SDL_JoystickNumAxes(pad[i]);
66                         WriteLog("Gamepad: Joystick #%i: %s\n", i, padName[i]);
67
68                         // Ick, kludges already!!!
69                         if (strcmp(padName[i], "Sony PLAYSTATION(R)3 Controller") == 0)
70                         {
71                                 // We do this because these axes stay stuck on -32000 (buttons)
72                                 // or come on and stay on (D-pad). :-P
73                                 numAxes[i] = 8;
74                                 WriteLog("Gamepad: Blacklisting PS3 controller axes 8 on up...\n");
75                         }
76                 }
77         }
78
79         WriteLog("Gamepad: Found %u joystick%s.\n", numJoysticks, (numJoysticks == 1 ? "" : "s"));
80 #if 0
81 for(int i=0; i<numJoysticks; i++)
82         printf("GAMEPAD::AllocateJoysticks: stick #%i = %s\n", i, padName[i]);
83 #endif
84 }
85
86
87 void Gamepad::DeallocateJoysticks(void)
88 {
89         for(int i=0; i<numJoysticks; i++)
90                 SDL_JoystickClose(pad[i]);
91 }
92
93
94 const char * Gamepad::GetJoystickName(int joystickID)
95 {
96         // Sanity check
97         if (joystickID >= 8)
98                 return NULL;
99
100 //printf("GAMEPAD: Getting name (%s) for joystick #%i...\n", padName[joystickID], joystickID);
101         return padName[joystickID];
102 }
103
104
105 bool Gamepad::GetState(int joystickID, int buttonID)
106 {
107         uint8_t hatMask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
108
109         if (buttonID & JOY_BUTTON)
110         {
111                 // Handle SDL button
112                 int buttonNum = (buttonID & JOY_BUTTON_MASK);
113                 return button[joystickID][buttonNum];
114         }
115         else if (buttonID & JOY_HAT)
116         {
117                 // Handle SDL hats
118                 int hatNumber = (buttonID & JOY_HATNUM_MASK) >> 3;
119                 uint8_t hatDirection = hatMask[buttonID & JOY_HATBUT_MASK];
120                 return (hat[joystickID][hatNumber] & hatDirection ? true : false);
121         }
122         else if (buttonID & JOY_AXIS)
123         {
124                 int axisNum = (buttonID & JOY_AXISNUM_MASK) >> 1;
125                 int direction = (buttonID & JOY_AXISDIR_MASK);
126 //printf("Checking pad #%u axis %u: axis = %i, direction = %u\n", joystickID, axisNum, axis[joystickID][axisNum], direction);
127
128                 if (axis[joystickID][axisNum] != 0)
129                 {
130                         if ((axis[joystickID][axisNum] > 32000) && (direction == 0))
131 //{
132 //printf("Axis + hit!\n");
133                                 return true;
134 //}
135
136                         if ((axis[joystickID][axisNum] < -32000) && (direction == 1))
137 //{
138 //printf("Axis - hit!\n");
139                                 return true;
140 //}
141                 }
142         }
143
144         // Default == failure
145         return false;
146 }
147
148
149 int Gamepad::CheckButtonPressed(void)
150 {
151         DumpJoystickStatesToLog();
152
153         // This translates the hat direction to a mask index.
154         int hatNum[16] = { -1, 0, 1, -1, 2, -1, -1, -1,
155                 3, -1, -1, -1, -1, -1, -1, -1 };
156
157         // Return single button ID being pressed (if any)
158         for(int i=0; i<numJoysticks; i++)
159         {
160                 for(int j=0; j<numButtons[i]; j++)
161                 {
162                         if (button[i][j])
163                                 return (JOY_BUTTON | j);
164                 }
165
166                 for(int j=0; j<numHats[i]; j++)
167                 {
168                         if (hat[i][j])
169                                 return (JOY_HAT | hatNum[hat[i][j]]);
170                 }
171
172                 for(int j=0; j<numAxes[i]; j++)
173                 {
174                         // We encode these as axis # (in bits 1-15), up or down in bit 0.
175 //                      if (axis[i][j] > 0)
176                         if (axis[i][j] > 32000)
177                                 return (JOY_AXIS | (j << 1) | 0);
178
179 //                      if (axis[i][j] < 0)
180                         if (axis[i][j] < -32000)
181                                 return (JOY_AXIS | (j << 1) | 1);
182                 }
183         }
184
185         return -1;
186 }
187
188
189 // UNUSED
190 int Gamepad::GetButtonID(void)
191 {
192         // Return single button ID being pressed (if any)
193         return -1;
194 }
195
196
197 // UNUSED
198 int Gamepad::GetJoystickID(void)
199 {
200         // Return joystick ID of button being pressed (if any)
201         return -1;
202 }
203
204
205 void Gamepad::Update(void)
206 {
207 //      SDL_PollEvent(&event);
208         SDL_JoystickUpdate();
209
210         for(int i=0; i<numJoysticks; i++)
211         {
212                 for(int j=0; j<numButtons[i]; j++)
213                         button[i][j] = SDL_JoystickGetButton(pad[i], j);
214
215                 for(int j=0; j<numHats[i]; j++)
216                         hat[i][j] = SDL_JoystickGetHat(pad[i], j);
217
218                 for(int j=0; j<numAxes[i]; j++)
219                         axis[i][j] = SDL_JoystickGetAxis(pad[i], j);
220         }
221 }
222
223
224 void Gamepad::DumpJoystickStatesToLog(void)
225 {
226         bool pressed = false;
227
228         for(int i=0; i<numJoysticks; i++)
229         {
230                 for(int j=0; j<numButtons[i]; j++)
231                 {
232                         if (button[i][j])
233                         {
234                                 pressed = true;
235                                 break;
236                                 break;
237                         }
238                 }
239
240                 for(int j=0; j<numHats[i]; j++)
241                 {
242                         if (hat[i][j])
243                         {
244                                 pressed = true;
245                                 break;
246                                 break;
247                         }
248                 }
249
250                 for(int j=0; j<numAxes[i]; j++)
251                 {
252                         // We encode these as axis # (in bits 1-15), up or down in bit 0.
253                         if (axis[i][j] > 32000)
254                         {
255                                 pressed = true;
256                                 break;
257                                 break;
258                         }
259
260                         if (axis[i][j] < -32000)
261                         {
262                                 pressed = true;
263                                 break;
264                                 break;
265                         }
266                 }
267         }
268
269         if (!pressed)
270                 return;
271
272         WriteLog("Gamepad: CheckButtonPressed...\n");
273
274         for(int i=0; i<numJoysticks; i++)
275         {
276                 for(int j=0; j<numButtons[i]; j++)
277                 {
278                         if (button[i][j])
279                                 WriteLog("Gamepad: Pad #%i, button %i down...\n", i, j);
280                 }
281
282                 for(int j=0; j<numHats[i]; j++)
283                 {
284                         if (hat[i][j])
285                                 WriteLog("Gamepad: Pad #%i, hat %i pushed...\n", i, j);
286                 }
287
288                 for(int j=0; j<numAxes[i]; j++)
289                 {
290                         // We encode these as axis # (in bits 1-15), up or down in bit 0.
291                         if (axis[i][j] > 32000)
292                                 WriteLog("Gamepad: Pad #%i, axis %i pushed down...\n", i, j);
293
294                         if (axis[i][j] < -32000)
295                                 WriteLog("Gamepad: Pad #%i, axis %i pushed up...\n", i, j);
296                 }
297         }
298 }
299
300
301 // However, SDL 2 *does* support hot-plugging! :-D
302 #if 0
303 // Need to test this. It may be that the only time joysticks are detected is
304 // when the program is first run. That would suck.
305 // Well, it turns out that SDL doesn't do hot plugging. :-(
306 void Gamepad::CheckConsistency(void)
307 {
308         int currentNumJoysticks = SDL_NumJoysticks();
309
310         // Check to see if the # of joysticks reported by SDL changed
311         if (currentNumJoysticks == numJoysticks)
312                 return;
313
314         // Either one or more joysticks were plugged in, or removed. Fix up our
315         // internal states to reflect this.
316
317         
318 }
319 #endif
320