1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "../../SDL_internal.h" |
22 | |
23 | #if defined(SDL_JOYSTICK_VIRTUAL) |
24 | |
25 | /* This is the virtual implementation of the SDL joystick API */ |
26 | |
27 | #include "SDL_virtualjoystick_c.h" |
28 | #include "../SDL_sysjoystick.h" |
29 | #include "../SDL_joystick_c.h" |
30 | |
31 | extern SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver; |
32 | |
33 | static joystick_hwdata * g_VJoys = NULL; |
34 | |
35 | |
36 | static joystick_hwdata * |
37 | VIRTUAL_HWDataForIndex(int device_index) |
38 | { |
39 | joystick_hwdata *vjoy = g_VJoys; |
40 | while (vjoy) { |
41 | if (device_index == 0) |
42 | break; |
43 | --device_index; |
44 | vjoy = vjoy->next; |
45 | } |
46 | return vjoy; |
47 | } |
48 | |
49 | |
50 | static void |
51 | VIRTUAL_FreeHWData(joystick_hwdata *hwdata) |
52 | { |
53 | joystick_hwdata * cur = g_VJoys; |
54 | joystick_hwdata * prev = NULL; |
55 | |
56 | if (!hwdata) { |
57 | return; |
58 | } |
59 | if (hwdata->axes) { |
60 | SDL_free((void *)hwdata->axes); |
61 | hwdata->axes = NULL; |
62 | } |
63 | if (hwdata->buttons) { |
64 | SDL_free((void *)hwdata->buttons); |
65 | hwdata->buttons = NULL; |
66 | } |
67 | if (hwdata->hats) { |
68 | SDL_free(hwdata->hats); |
69 | hwdata->hats = NULL; |
70 | } |
71 | |
72 | /* Remove hwdata from SDL-global list */ |
73 | while (cur) { |
74 | if (hwdata == cur) { |
75 | if (prev) { |
76 | prev->next = cur->next; |
77 | } else { |
78 | g_VJoys = cur->next; |
79 | } |
80 | break; |
81 | } |
82 | prev = cur; |
83 | cur = cur->next; |
84 | } |
85 | |
86 | SDL_free(hwdata); |
87 | } |
88 | |
89 | |
90 | int |
91 | SDL_JoystickAttachVirtualInner(SDL_JoystickType type, |
92 | int naxes, |
93 | int nbuttons, |
94 | int nhats) |
95 | { |
96 | joystick_hwdata *hwdata = NULL; |
97 | int device_index = -1; |
98 | |
99 | hwdata = SDL_calloc(1, sizeof(joystick_hwdata)); |
100 | if (!hwdata) { |
101 | VIRTUAL_FreeHWData(hwdata); |
102 | return SDL_OutOfMemory(); |
103 | } |
104 | |
105 | hwdata->naxes = naxes; |
106 | hwdata->nbuttons = nbuttons; |
107 | hwdata->nhats = nhats; |
108 | hwdata->name = "Virtual Joystick" ; |
109 | |
110 | /* Note that this is a Virtual device and what subtype it is */ |
111 | hwdata->guid.data[14] = 'v'; |
112 | hwdata->guid.data[15] = (Uint8)type; |
113 | |
114 | /* Allocate fields for different control-types */ |
115 | if (naxes > 0) { |
116 | hwdata->axes = SDL_calloc(naxes, sizeof(Sint16)); |
117 | if (!hwdata->axes) { |
118 | VIRTUAL_FreeHWData(hwdata); |
119 | return SDL_OutOfMemory(); |
120 | } |
121 | } |
122 | if (nbuttons > 0) { |
123 | hwdata->buttons = SDL_calloc(nbuttons, sizeof(Uint8)); |
124 | if (!hwdata->buttons) { |
125 | VIRTUAL_FreeHWData(hwdata); |
126 | return SDL_OutOfMemory(); |
127 | } |
128 | } |
129 | if (nhats > 0) { |
130 | hwdata->hats = SDL_calloc(nhats, sizeof(Uint8)); |
131 | if (!hwdata->hats) { |
132 | VIRTUAL_FreeHWData(hwdata); |
133 | return SDL_OutOfMemory(); |
134 | } |
135 | } |
136 | |
137 | /* Allocate an instance ID for this device */ |
138 | hwdata->instance_id = SDL_GetNextJoystickInstanceID(); |
139 | |
140 | /* Add virtual joystick to SDL-global lists */ |
141 | hwdata->next = g_VJoys; |
142 | g_VJoys = hwdata; |
143 | SDL_PrivateJoystickAdded(hwdata->instance_id); |
144 | |
145 | /* Return the new virtual-device's index */ |
146 | device_index = SDL_JoystickGetDeviceIndexFromInstanceID(hwdata->instance_id); |
147 | return device_index; |
148 | } |
149 | |
150 | |
151 | int |
152 | SDL_JoystickDetachVirtualInner(int device_index) |
153 | { |
154 | SDL_JoystickID instance_id; |
155 | joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); |
156 | if (!hwdata) { |
157 | return SDL_SetError("Virtual joystick data not found" ); |
158 | } |
159 | instance_id = hwdata->instance_id; |
160 | VIRTUAL_FreeHWData(hwdata); |
161 | SDL_PrivateJoystickRemoved(instance_id); |
162 | return 0; |
163 | } |
164 | |
165 | |
166 | int |
167 | SDL_JoystickSetVirtualAxisInner(SDL_Joystick * joystick, int axis, Sint16 value) |
168 | { |
169 | joystick_hwdata *hwdata; |
170 | |
171 | SDL_LockJoysticks(); |
172 | |
173 | if (!joystick || !joystick->hwdata) { |
174 | SDL_UnlockJoysticks(); |
175 | return SDL_SetError("Invalid joystick" ); |
176 | } |
177 | |
178 | hwdata = (joystick_hwdata *)joystick->hwdata; |
179 | if (axis < 0 || axis >= hwdata->nbuttons) { |
180 | SDL_UnlockJoysticks(); |
181 | return SDL_SetError("Invalid axis index" ); |
182 | } |
183 | |
184 | hwdata->axes[axis] = value; |
185 | |
186 | SDL_UnlockJoysticks(); |
187 | return 0; |
188 | } |
189 | |
190 | |
191 | int |
192 | SDL_JoystickSetVirtualButtonInner(SDL_Joystick * joystick, int button, Uint8 value) |
193 | { |
194 | joystick_hwdata *hwdata; |
195 | |
196 | SDL_LockJoysticks(); |
197 | |
198 | if (!joystick || !joystick->hwdata) { |
199 | SDL_UnlockJoysticks(); |
200 | return SDL_SetError("Invalid joystick" ); |
201 | } |
202 | |
203 | hwdata = (joystick_hwdata *)joystick->hwdata; |
204 | if (button < 0 || button >= hwdata->nbuttons) { |
205 | SDL_UnlockJoysticks(); |
206 | return SDL_SetError("Invalid button index" ); |
207 | } |
208 | |
209 | hwdata->buttons[button] = value; |
210 | |
211 | SDL_UnlockJoysticks(); |
212 | return 0; |
213 | } |
214 | |
215 | |
216 | int |
217 | SDL_JoystickSetVirtualHatInner(SDL_Joystick * joystick, int hat, Uint8 value) |
218 | { |
219 | joystick_hwdata *hwdata; |
220 | |
221 | SDL_LockJoysticks(); |
222 | |
223 | if (!joystick || !joystick->hwdata) { |
224 | SDL_UnlockJoysticks(); |
225 | return SDL_SetError("Invalid joystick" ); |
226 | } |
227 | |
228 | hwdata = (joystick_hwdata *)joystick->hwdata; |
229 | if (hat < 0 || hat >= hwdata->nbuttons) { |
230 | SDL_UnlockJoysticks(); |
231 | return SDL_SetError("Invalid hat index" ); |
232 | } |
233 | |
234 | hwdata->hats[hat] = value; |
235 | |
236 | SDL_UnlockJoysticks(); |
237 | return 0; |
238 | } |
239 | |
240 | |
241 | static int |
242 | VIRTUAL_JoystickInit(void) |
243 | { |
244 | return 0; |
245 | } |
246 | |
247 | |
248 | static int |
249 | VIRTUAL_JoystickGetCount(void) |
250 | { |
251 | int count = 0; |
252 | joystick_hwdata *cur = g_VJoys; |
253 | while (cur) { |
254 | ++count; |
255 | cur = cur->next; |
256 | } |
257 | return count; |
258 | } |
259 | |
260 | |
261 | static void |
262 | VIRTUAL_JoystickDetect(void) |
263 | { |
264 | } |
265 | |
266 | |
267 | static const char * |
268 | VIRTUAL_JoystickGetDeviceName(int device_index) |
269 | { |
270 | joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); |
271 | if (!hwdata) { |
272 | return NULL; |
273 | } |
274 | return hwdata->name ? hwdata->name : "" ; |
275 | } |
276 | |
277 | |
278 | static int |
279 | VIRTUAL_JoystickGetDevicePlayerIndex(int device_index) |
280 | { |
281 | return -1; |
282 | } |
283 | |
284 | |
285 | static void |
286 | VIRTUAL_JoystickSetDevicePlayerIndex(int device_index, int player_index) |
287 | { |
288 | } |
289 | |
290 | |
291 | static SDL_JoystickGUID |
292 | VIRTUAL_JoystickGetDeviceGUID(int device_index) |
293 | { |
294 | joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); |
295 | if (!hwdata) { |
296 | SDL_JoystickGUID guid; |
297 | SDL_zero(guid); |
298 | return guid; |
299 | } |
300 | return hwdata->guid; |
301 | } |
302 | |
303 | |
304 | static SDL_JoystickID |
305 | VIRTUAL_JoystickGetDeviceInstanceID(int device_index) |
306 | { |
307 | joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); |
308 | if (!hwdata) { |
309 | return -1; |
310 | } |
311 | return hwdata->instance_id; |
312 | } |
313 | |
314 | |
315 | static int |
316 | VIRTUAL_JoystickOpen(SDL_Joystick * joystick, int device_index) |
317 | { |
318 | joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); |
319 | if (!hwdata) { |
320 | return SDL_SetError("No such device" ); |
321 | } |
322 | if (hwdata->opened) { |
323 | return SDL_SetError("Joystick already opened" ); |
324 | } |
325 | joystick->instance_id = hwdata->instance_id; |
326 | joystick->hwdata = hwdata; |
327 | joystick->naxes = hwdata->naxes; |
328 | joystick->nbuttons = hwdata->nbuttons; |
329 | joystick->nhats = hwdata->nhats; |
330 | hwdata->opened = SDL_TRUE; |
331 | return 0; |
332 | } |
333 | |
334 | |
335 | static int |
336 | VIRTUAL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) |
337 | { |
338 | return SDL_Unsupported(); |
339 | } |
340 | |
341 | static int |
342 | VIRTUAL_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) |
343 | { |
344 | return SDL_Unsupported(); |
345 | } |
346 | |
347 | |
348 | static SDL_bool |
349 | VIRTUAL_JoystickHasLED(SDL_Joystick * joystick) |
350 | { |
351 | return SDL_FALSE; |
352 | } |
353 | |
354 | |
355 | static int |
356 | VIRTUAL_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) |
357 | { |
358 | return SDL_Unsupported(); |
359 | } |
360 | |
361 | static int |
362 | VIRTUAL_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) |
363 | { |
364 | return SDL_Unsupported(); |
365 | } |
366 | |
367 | |
368 | static void |
369 | VIRTUAL_JoystickUpdate(SDL_Joystick * joystick) |
370 | { |
371 | joystick_hwdata *hwdata; |
372 | int i; |
373 | |
374 | if (!joystick) { |
375 | return; |
376 | } |
377 | if (!joystick->hwdata) { |
378 | return; |
379 | } |
380 | |
381 | hwdata = (joystick_hwdata *)joystick->hwdata; |
382 | |
383 | for (i = 0; i < hwdata->naxes; ++i) { |
384 | SDL_PrivateJoystickAxis(joystick, i, hwdata->axes[i]); |
385 | } |
386 | for (i = 0; i < hwdata->nbuttons; ++i) { |
387 | SDL_PrivateJoystickButton(joystick, i, hwdata->buttons[i]); |
388 | } |
389 | for (i = 0; i < hwdata->nhats; ++i) { |
390 | SDL_PrivateJoystickHat(joystick, i, hwdata->hats[i]); |
391 | } |
392 | } |
393 | |
394 | |
395 | static void |
396 | VIRTUAL_JoystickClose(SDL_Joystick * joystick) |
397 | { |
398 | joystick_hwdata *hwdata; |
399 | |
400 | if (!joystick) { |
401 | return; |
402 | } |
403 | if (!joystick->hwdata) { |
404 | return; |
405 | } |
406 | |
407 | hwdata = (joystick_hwdata *)joystick->hwdata; |
408 | hwdata->opened = SDL_FALSE; |
409 | } |
410 | |
411 | |
412 | static void |
413 | VIRTUAL_JoystickQuit(void) |
414 | { |
415 | while (g_VJoys) { |
416 | VIRTUAL_FreeHWData(g_VJoys); |
417 | } |
418 | } |
419 | |
420 | static SDL_bool |
421 | VIRTUAL_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) |
422 | { |
423 | return SDL_FALSE; |
424 | } |
425 | |
426 | SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver = |
427 | { |
428 | VIRTUAL_JoystickInit, |
429 | VIRTUAL_JoystickGetCount, |
430 | VIRTUAL_JoystickDetect, |
431 | VIRTUAL_JoystickGetDeviceName, |
432 | VIRTUAL_JoystickGetDevicePlayerIndex, |
433 | VIRTUAL_JoystickSetDevicePlayerIndex, |
434 | VIRTUAL_JoystickGetDeviceGUID, |
435 | VIRTUAL_JoystickGetDeviceInstanceID, |
436 | VIRTUAL_JoystickOpen, |
437 | VIRTUAL_JoystickRumble, |
438 | VIRTUAL_JoystickRumbleTriggers, |
439 | VIRTUAL_JoystickHasLED, |
440 | VIRTUAL_JoystickSetLED, |
441 | VIRTUAL_JoystickSetSensorsEnabled, |
442 | VIRTUAL_JoystickUpdate, |
443 | VIRTUAL_JoystickClose, |
444 | VIRTUAL_JoystickQuit, |
445 | VIRTUAL_JoystickGetGamepadMapping |
446 | }; |
447 | |
448 | #endif /* SDL_JOYSTICK_VIRTUAL */ |
449 | |
450 | /* vi: set ts=4 sw=4 expandtab: */ |
451 | |