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
31extern SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver;
32
33static joystick_hwdata * g_VJoys = NULL;
34
35
36static joystick_hwdata *
37VIRTUAL_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
50static void
51VIRTUAL_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
90int
91SDL_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
151int
152SDL_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
166int
167SDL_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
191int
192SDL_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
216int
217SDL_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
241static int
242VIRTUAL_JoystickInit(void)
243{
244 return 0;
245}
246
247
248static int
249VIRTUAL_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
261static void
262VIRTUAL_JoystickDetect(void)
263{
264}
265
266
267static const char *
268VIRTUAL_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
278static int
279VIRTUAL_JoystickGetDevicePlayerIndex(int device_index)
280{
281 return -1;
282}
283
284
285static void
286VIRTUAL_JoystickSetDevicePlayerIndex(int device_index, int player_index)
287{
288}
289
290
291static SDL_JoystickGUID
292VIRTUAL_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
304static SDL_JoystickID
305VIRTUAL_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
315static int
316VIRTUAL_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
335static int
336VIRTUAL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
337{
338 return SDL_Unsupported();
339}
340
341static int
342VIRTUAL_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
343{
344 return SDL_Unsupported();
345}
346
347
348static SDL_bool
349VIRTUAL_JoystickHasLED(SDL_Joystick * joystick)
350{
351 return SDL_FALSE;
352}
353
354
355static int
356VIRTUAL_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue)
357{
358 return SDL_Unsupported();
359}
360
361static int
362VIRTUAL_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
363{
364 return SDL_Unsupported();
365}
366
367
368static void
369VIRTUAL_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
395static void
396VIRTUAL_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
412static void
413VIRTUAL_JoystickQuit(void)
414{
415 while (g_VJoys) {
416 VIRTUAL_FreeHWData(g_VJoys);
417 }
418}
419
420static SDL_bool
421VIRTUAL_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
422{
423 return SDL_FALSE;
424}
425
426SDL_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