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