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 *
VIRTUAL_HWDataForIndex(int device_index)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
VIRTUAL_FreeHWData(joystick_hwdata * hwdata)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
SDL_JoystickAttachVirtualInner(SDL_JoystickType type,int naxes,int nbuttons,int nhats)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
SDL_JoystickDetachVirtualInner(int device_index)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
SDL_JoystickSetVirtualAxisInner(SDL_Joystick * joystick,int axis,Sint16 value)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->naxes) {
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
SDL_JoystickSetVirtualButtonInner(SDL_Joystick * joystick,int button,Uint8 value)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
SDL_JoystickSetVirtualHatInner(SDL_Joystick * joystick,int hat,Uint8 value)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->nhats) {
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
VIRTUAL_JoystickInit(void)242 VIRTUAL_JoystickInit(void)
243 {
244 return 0;
245 }
246
247
248 static int
VIRTUAL_JoystickGetCount(void)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
VIRTUAL_JoystickDetect(void)262 VIRTUAL_JoystickDetect(void)
263 {
264 }
265
266
267 static const char *
VIRTUAL_JoystickGetDeviceName(int device_index)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
VIRTUAL_JoystickGetDevicePlayerIndex(int device_index)279 VIRTUAL_JoystickGetDevicePlayerIndex(int device_index)
280 {
281 return -1;
282 }
283
284
285 static void
VIRTUAL_JoystickSetDevicePlayerIndex(int device_index,int player_index)286 VIRTUAL_JoystickSetDevicePlayerIndex(int device_index, int player_index)
287 {
288 }
289
290
291 static SDL_JoystickGUID
VIRTUAL_JoystickGetDeviceGUID(int device_index)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
VIRTUAL_JoystickGetDeviceInstanceID(int device_index)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
VIRTUAL_JoystickOpen(SDL_Joystick * joystick,int device_index)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
VIRTUAL_JoystickRumble(SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)336 VIRTUAL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
337 {
338 return SDL_Unsupported();
339 }
340
341 static int
VIRTUAL_JoystickRumbleTriggers(SDL_Joystick * joystick,Uint16 left_rumble,Uint16 right_rumble)342 VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
343 {
344 return SDL_Unsupported();
345 }
346
347
348 static Uint32
VIRTUAL_JoystickGetCapabilities(SDL_Joystick * joystick)349 VIRTUAL_JoystickGetCapabilities(SDL_Joystick *joystick)
350 {
351 return 0;
352 }
353
354
355 static int
VIRTUAL_JoystickSetLED(SDL_Joystick * joystick,Uint8 red,Uint8 green,Uint8 blue)356 VIRTUAL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
357 {
358 return SDL_Unsupported();
359 }
360
361 static int
VIRTUAL_JoystickSendEffect(SDL_Joystick * joystick,const void * data,int size)362 VIRTUAL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
363 {
364 return SDL_Unsupported();
365 }
366
367 static int
VIRTUAL_JoystickSetSensorsEnabled(SDL_Joystick * joystick,SDL_bool enabled)368 VIRTUAL_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
369 {
370 return SDL_Unsupported();
371 }
372
373
374 static void
VIRTUAL_JoystickUpdate(SDL_Joystick * joystick)375 VIRTUAL_JoystickUpdate(SDL_Joystick *joystick)
376 {
377 joystick_hwdata *hwdata;
378 int i;
379
380 if (!joystick) {
381 return;
382 }
383 if (!joystick->hwdata) {
384 return;
385 }
386
387 hwdata = (joystick_hwdata *)joystick->hwdata;
388
389 for (i = 0; i < hwdata->naxes; ++i) {
390 SDL_PrivateJoystickAxis(joystick, i, hwdata->axes[i]);
391 }
392 for (i = 0; i < hwdata->nbuttons; ++i) {
393 SDL_PrivateJoystickButton(joystick, i, hwdata->buttons[i]);
394 }
395 for (i = 0; i < hwdata->nhats; ++i) {
396 SDL_PrivateJoystickHat(joystick, i, hwdata->hats[i]);
397 }
398 }
399
400
401 static void
VIRTUAL_JoystickClose(SDL_Joystick * joystick)402 VIRTUAL_JoystickClose(SDL_Joystick *joystick)
403 {
404 joystick_hwdata *hwdata;
405
406 if (!joystick) {
407 return;
408 }
409 if (!joystick->hwdata) {
410 return;
411 }
412
413 hwdata = (joystick_hwdata *)joystick->hwdata;
414 hwdata->opened = SDL_FALSE;
415 }
416
417
418 static void
VIRTUAL_JoystickQuit(void)419 VIRTUAL_JoystickQuit(void)
420 {
421 while (g_VJoys) {
422 VIRTUAL_FreeHWData(g_VJoys);
423 }
424 }
425
426 static SDL_bool
VIRTUAL_JoystickGetGamepadMapping(int device_index,SDL_GamepadMapping * out)427 VIRTUAL_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
428 {
429 return SDL_FALSE;
430 }
431
432 SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver =
433 {
434 VIRTUAL_JoystickInit,
435 VIRTUAL_JoystickGetCount,
436 VIRTUAL_JoystickDetect,
437 VIRTUAL_JoystickGetDeviceName,
438 VIRTUAL_JoystickGetDevicePlayerIndex,
439 VIRTUAL_JoystickSetDevicePlayerIndex,
440 VIRTUAL_JoystickGetDeviceGUID,
441 VIRTUAL_JoystickGetDeviceInstanceID,
442 VIRTUAL_JoystickOpen,
443 VIRTUAL_JoystickRumble,
444 VIRTUAL_JoystickRumbleTriggers,
445 VIRTUAL_JoystickGetCapabilities,
446 VIRTUAL_JoystickSetLED,
447 VIRTUAL_JoystickSendEffect,
448 VIRTUAL_JoystickSetSensorsEnabled,
449 VIRTUAL_JoystickUpdate,
450 VIRTUAL_JoystickClose,
451 VIRTUAL_JoystickQuit,
452 VIRTUAL_JoystickGetGamepadMapping
453 };
454
455 #endif /* SDL_JOYSTICK_VIRTUAL */
456
457 /* vi: set ts=4 sw=4 expandtab: */
458