Commit | Line | Data |
---|---|---|
cf76e892 JPM |
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 -32767 (buttons) | |
72 | // or start at 0 and stay stuck at -32767 (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 |