1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 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->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
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->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
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
342 static void
VIRTUAL_JoystickUpdate(SDL_Joystick * joystick)343 VIRTUAL_JoystickUpdate(SDL_Joystick * joystick)
344 {
345 joystick_hwdata *hwdata;
346 int i;
347
348 if (!joystick) {
349 return;
350 }
351 if (!joystick->hwdata) {
352 return;
353 }
354
355 hwdata = (joystick_hwdata *)joystick->hwdata;
356
357 for (i = 0; i < hwdata->naxes; ++i) {
358 SDL_PrivateJoystickAxis(joystick, i, hwdata->axes[i]);
359 }
360 for (i = 0; i < hwdata->nbuttons; ++i) {
361 SDL_PrivateJoystickButton(joystick, i, hwdata->buttons[i]);
362 }
363 for (i = 0; i < hwdata->nhats; ++i) {
364 SDL_PrivateJoystickHat(joystick, i, hwdata->hats[i]);
365 }
366 }
367
368
369 static void
VIRTUAL_JoystickClose(SDL_Joystick * joystick)370 VIRTUAL_JoystickClose(SDL_Joystick * joystick)
371 {
372 joystick_hwdata *hwdata;
373
374 if (!joystick) {
375 return;
376 }
377 if (!joystick->hwdata) {
378 return;
379 }
380
381 hwdata = (joystick_hwdata *)joystick->hwdata;
382 hwdata->opened = SDL_FALSE;
383 }
384
385
386 static void
VIRTUAL_JoystickQuit(void)387 VIRTUAL_JoystickQuit(void)
388 {
389 while (g_VJoys) {
390 VIRTUAL_FreeHWData(g_VJoys);
391 }
392 }
393
394 static SDL_bool
VIRTUAL_JoystickGetGamepadMapping(int device_index,SDL_GamepadMapping * out)395 VIRTUAL_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
396 {
397 return SDL_FALSE;
398 }
399
400 SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver =
401 {
402 VIRTUAL_JoystickInit,
403 VIRTUAL_JoystickGetCount,
404 VIRTUAL_JoystickDetect,
405 VIRTUAL_JoystickGetDeviceName,
406 VIRTUAL_JoystickGetDevicePlayerIndex,
407 VIRTUAL_JoystickSetDevicePlayerIndex,
408 VIRTUAL_JoystickGetDeviceGUID,
409 VIRTUAL_JoystickGetDeviceInstanceID,
410 VIRTUAL_JoystickOpen,
411 VIRTUAL_JoystickRumble,
412 VIRTUAL_JoystickUpdate,
413 VIRTUAL_JoystickClose,
414 VIRTUAL_JoystickQuit,
415 VIRTUAL_JoystickGetGamepadMapping
416 };
417
418 #endif /* SDL_JOYSTICK_VIRTUAL || SDL_JOYSTICK_DISABLED */
419
420 /* vi: set ts=4 sw=4 expandtab: */
421