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 #ifdef SDL_JOYSTICK_HIDAPI
24
25 #include "SDL_hints.h"
26 #include "SDL_events.h"
27 #include "SDL_joystick.h"
28 #include "SDL_gamecontroller.h"
29 #include "../SDL_sysjoystick.h"
30 #include "SDL_hidapijoystick_c.h"
31 #include "SDL_hidapi_rumble.h"
32
33
34 #ifdef SDL_JOYSTICK_HIDAPI_LUNA
35
36 /* Define this if you want to log all packets from the controller */
37 /*#define DEBUG_LUNA_PROTOCOL*/
38
39 enum
40 {
41 SDL_CONTROLLER_BUTTON_LUNA_MIC = 15,
42 SDL_CONTROLLER_NUM_LUNA_BUTTONS,
43 };
44
45 typedef struct {
46 Uint8 last_state[USB_PACKET_LENGTH];
47 } SDL_DriverLuna_Context;
48
49
50 static SDL_bool
HIDAPI_DriverLuna_IsSupportedDevice(const char * name,SDL_GameControllerType type,Uint16 vendor_id,Uint16 product_id,Uint16 version,int interface_number,int interface_class,int interface_subclass,int interface_protocol)51 HIDAPI_DriverLuna_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
52 {
53 return (type == SDL_CONTROLLER_TYPE_AMAZON_LUNA) ? SDL_TRUE : SDL_FALSE;
54 }
55
56 static const char *
HIDAPI_DriverLuna_GetDeviceName(Uint16 vendor_id,Uint16 product_id)57 HIDAPI_DriverLuna_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
58 {
59 return "Amazon Luna Controller";
60 }
61
62 static SDL_bool
HIDAPI_DriverLuna_InitDevice(SDL_HIDAPI_Device * device)63 HIDAPI_DriverLuna_InitDevice(SDL_HIDAPI_Device *device)
64 {
65 return HIDAPI_JoystickConnected(device, NULL);
66 }
67
68 static int
HIDAPI_DriverLuna_GetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id)69 HIDAPI_DriverLuna_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
70 {
71 return -1;
72 }
73
74 static void
HIDAPI_DriverLuna_SetDevicePlayerIndex(SDL_HIDAPI_Device * device,SDL_JoystickID instance_id,int player_index)75 HIDAPI_DriverLuna_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
76 {
77 }
78
79 static SDL_bool
HIDAPI_DriverLuna_OpenJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)80 HIDAPI_DriverLuna_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
81 {
82 SDL_DriverLuna_Context *ctx;
83
84 ctx = (SDL_DriverLuna_Context *)SDL_calloc(1, sizeof(*ctx));
85 if (!ctx) {
86 SDL_OutOfMemory();
87 return SDL_FALSE;
88 }
89
90 device->dev = SDL_hid_open_path(device->path, 0);
91 if (!device->dev) {
92 SDL_SetError("Couldn't open %s", device->path);
93 SDL_free(ctx);
94 return SDL_FALSE;
95 }
96 device->context = ctx;
97
98 /* Initialize the joystick capabilities */
99 joystick->nbuttons = SDL_CONTROLLER_NUM_LUNA_BUTTONS;
100 joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
101 joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
102 joystick->serial = NULL;
103
104 return SDL_TRUE;
105 }
106
107 static int
HIDAPI_DriverLuna_RumbleJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)108 HIDAPI_DriverLuna_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
109 {
110 if (device->product_id == BLUETOOTH_PRODUCT_LUNA_CONTROLLER) {
111 /* Same packet as on Xbox One controllers connected via Bluetooth */
112 Uint8 rumble_packet[] = { 0x03, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xEB };
113
114 /* Magnitude is 1..100 so scale the 16-bit input here */
115 rumble_packet[4] = low_frequency_rumble / 655;
116 rumble_packet[5] = high_frequency_rumble / 655;
117
118 if (SDL_HIDAPI_SendRumble(device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
119 return SDL_SetError("Couldn't send rumble packet");
120 }
121
122 return 0;
123 } else {
124 /* FIXME: Is there a rumble packet over USB? */
125 return SDL_Unsupported();
126 }
127 }
128
129 static int
HIDAPI_DriverLuna_RumbleJoystickTriggers(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint16 left_rumble,Uint16 right_rumble)130 HIDAPI_DriverLuna_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
131 {
132 return SDL_Unsupported();
133 }
134
135 static Uint32
HIDAPI_DriverLuna_GetJoystickCapabilities(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)136 HIDAPI_DriverLuna_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
137 {
138 Uint32 result = 0;
139
140 if (device->product_id == BLUETOOTH_PRODUCT_LUNA_CONTROLLER) {
141 result |= SDL_JOYCAP_RUMBLE;
142 }
143
144 return result;
145 }
146
147 static int
HIDAPI_DriverLuna_SetJoystickLED(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,Uint8 red,Uint8 green,Uint8 blue)148 HIDAPI_DriverLuna_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
149 {
150 return SDL_Unsupported();
151 }
152
153 static int
HIDAPI_DriverLuna_SendJoystickEffect(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,const void * data,int size)154 HIDAPI_DriverLuna_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
155 {
156 return SDL_Unsupported();
157 }
158
159 static int
HIDAPI_DriverLuna_SetJoystickSensorsEnabled(SDL_HIDAPI_Device * device,SDL_Joystick * joystick,SDL_bool enabled)160 HIDAPI_DriverLuna_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
161 {
162 return SDL_Unsupported();
163 }
164
165 static void
HIDAPI_DriverLuna_HandleUSBStatePacket(SDL_Joystick * joystick,SDL_DriverLuna_Context * ctx,Uint8 * data,int size)166 HIDAPI_DriverLuna_HandleUSBStatePacket(SDL_Joystick *joystick, SDL_DriverLuna_Context *ctx, Uint8 *data, int size)
167 {
168 if (ctx->last_state[1] != data[1]) {
169 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[1] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
170 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[1] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
171 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[1] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
172 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[1] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
173 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[1] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
174 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[1] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
175 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[1] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
176 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[1] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
177 }
178 if (ctx->last_state[2] != data[2]) {
179 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[2] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
180 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LUNA_MIC, (data[2] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
181 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[2] & 0x04) ? SDL_PRESSED : SDL_RELEASED);
182 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[2] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
183 }
184
185 if (ctx->last_state[3] != data[3]) {
186 SDL_bool dpad_up = SDL_FALSE;
187 SDL_bool dpad_down = SDL_FALSE;
188 SDL_bool dpad_left = SDL_FALSE;
189 SDL_bool dpad_right = SDL_FALSE;
190
191 switch (data[3] & 0xf) {
192 case 0:
193 dpad_up = SDL_TRUE;
194 break;
195 case 1:
196 dpad_up = SDL_TRUE;
197 dpad_right = SDL_TRUE;
198 break;
199 case 2:
200 dpad_right = SDL_TRUE;
201 break;
202 case 3:
203 dpad_right = SDL_TRUE;
204 dpad_down = SDL_TRUE;
205 break;
206 case 4:
207 dpad_down = SDL_TRUE;
208 break;
209 case 5:
210 dpad_left = SDL_TRUE;
211 dpad_down = SDL_TRUE;
212 break;
213 case 6:
214 dpad_left = SDL_TRUE;
215 break;
216 case 7:
217 dpad_up = SDL_TRUE;
218 dpad_left = SDL_TRUE;
219 break;
220 default:
221 break;
222 }
223 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
224 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
225 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
226 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
227 }
228
229 #define READ_STICK_AXIS(offset) \
230 (data[offset] == 0x7f ? 0 : \
231 (Sint16)HIDAPI_RemapVal((float)data[offset], 0x00, 0xff, SDL_MIN_SINT16, SDL_MAX_SINT16))
232 {
233 Sint16 axis = READ_STICK_AXIS(4);
234 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
235 axis = READ_STICK_AXIS(5);
236 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
237 axis = READ_STICK_AXIS(6);
238 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
239 axis = READ_STICK_AXIS(7);
240 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
241 }
242 #undef READ_STICK_AXIS
243
244 #define READ_TRIGGER_AXIS(offset) \
245 (Sint16)HIDAPI_RemapVal((float)data[offset], 0x00, 0xff, SDL_MIN_SINT16, SDL_MAX_SINT16)
246 {
247 Sint16 axis = READ_TRIGGER_AXIS(8);
248 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
249 axis = READ_TRIGGER_AXIS(9);
250 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
251 }
252 #undef READ_TRIGGER_AXIS
253
254 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
255 }
256
257 static void
HIDAPI_DriverLuna_HandleBluetoothStatePacket(SDL_Joystick * joystick,SDL_DriverLuna_Context * ctx,Uint8 * data,int size)258 HIDAPI_DriverLuna_HandleBluetoothStatePacket(SDL_Joystick *joystick, SDL_DriverLuna_Context *ctx, Uint8 *data, int size)
259 {
260 if (size >= 2 && data[0] == 0x02) {
261 /* Home button has dedicated report */
262 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data[1] & 0x1) ? SDL_PRESSED : SDL_RELEASED);
263 return;
264 }
265
266 if (size >= 2 && data[0] == 0x04) {
267 /* Battery level report */
268 int level = data[1] * 100 / 0xFF;
269 if (level == 0) {
270 joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
271 }
272 else if (level <= 20) {
273 joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
274 }
275 else if (level <= 70) {
276 joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
277 }
278 else {
279 joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
280 }
281
282 return;
283 }
284
285 if (size < 17 || data[0] != 0x01) {
286 /* We don't know how to handle this report */
287 return;
288 }
289
290 if (ctx->last_state[13] != data[13]) {
291 SDL_bool dpad_up = SDL_FALSE;
292 SDL_bool dpad_down = SDL_FALSE;
293 SDL_bool dpad_left = SDL_FALSE;
294 SDL_bool dpad_right = SDL_FALSE;
295
296 switch (data[13] & 0xf) {
297 case 1:
298 dpad_up = SDL_TRUE;
299 break;
300 case 2:
301 dpad_up = SDL_TRUE;
302 dpad_right = SDL_TRUE;
303 break;
304 case 3:
305 dpad_right = SDL_TRUE;
306 break;
307 case 4:
308 dpad_right = SDL_TRUE;
309 dpad_down = SDL_TRUE;
310 break;
311 case 5:
312 dpad_down = SDL_TRUE;
313 break;
314 case 6:
315 dpad_left = SDL_TRUE;
316 dpad_down = SDL_TRUE;
317 break;
318 case 7:
319 dpad_left = SDL_TRUE;
320 break;
321 case 8:
322 dpad_up = SDL_TRUE;
323 dpad_left = SDL_TRUE;
324 break;
325 default:
326 break;
327 }
328 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
329 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
330 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
331 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
332 }
333
334 if (ctx->last_state[14] != data[14]) {
335 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data[14] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
336 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data[14] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
337 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data[14] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
338 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data[14] & 0x10) ? SDL_PRESSED : SDL_RELEASED);
339 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data[14] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
340 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data[14] & 0x80) ? SDL_PRESSED : SDL_RELEASED);
341 }
342 if (ctx->last_state[15] != data[15]) {
343 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data[15] & 0x08) ? SDL_PRESSED : SDL_RELEASED);
344 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data[15] & 0x20) ? SDL_PRESSED : SDL_RELEASED);
345 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data[15] & 0x40) ? SDL_PRESSED : SDL_RELEASED);
346 }
347 if (ctx->last_state[16] != data[16]) {
348 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data[16] & 0x01) ? SDL_PRESSED : SDL_RELEASED);
349 SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LUNA_MIC, (data[16] & 0x02) ? SDL_PRESSED : SDL_RELEASED);
350 }
351
352 #define READ_STICK_AXIS(offset) \
353 (data[offset] == 0x7f ? 0 : \
354 (Sint16)HIDAPI_RemapVal((float)data[offset], 0x00, 0xff, SDL_MIN_SINT16, SDL_MAX_SINT16))
355 {
356 Sint16 axis = READ_STICK_AXIS(2);
357 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
358 axis = READ_STICK_AXIS(4);
359 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
360 axis = READ_STICK_AXIS(6);
361 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
362 axis = READ_STICK_AXIS(8);
363 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
364 }
365 #undef READ_STICK_AXIS
366
367 #define READ_TRIGGER_AXIS(offset) \
368 (Sint16)HIDAPI_RemapVal((float)((int)(((data[offset] | (data[offset + 1] << 8)) & 0x3ff) - 0x200)), 0x00 - 0x200, 0x3ff - 0x200, SDL_MIN_SINT16, SDL_MAX_SINT16)
369 {
370 Sint16 axis = READ_TRIGGER_AXIS(9);
371 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
372 axis = READ_TRIGGER_AXIS(11);
373 SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
374 }
375 #undef READ_TRIGGER_AXIS
376
377 SDL_memcpy(ctx->last_state, data, SDL_min(size, sizeof(ctx->last_state)));
378 }
379
380 static SDL_bool
HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device * device)381 HIDAPI_DriverLuna_UpdateDevice(SDL_HIDAPI_Device *device)
382 {
383 SDL_DriverLuna_Context *ctx = (SDL_DriverLuna_Context *)device->context;
384 SDL_Joystick *joystick = NULL;
385 Uint8 data[USB_PACKET_LENGTH];
386 int size = 0;
387
388 if (device->num_joysticks > 0) {
389 joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
390 }
391 if (!joystick) {
392 return SDL_FALSE;
393 }
394
395 while ((size = SDL_hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) {
396 #ifdef DEBUG_LUNA_PROTOCOL
397 HIDAPI_DumpPacket("Amazon Luna packet: size = %d", data, size);
398 #endif
399 switch (size) {
400 case 10:
401 HIDAPI_DriverLuna_HandleUSBStatePacket(joystick, ctx, data, size);
402 break;
403 default:
404 HIDAPI_DriverLuna_HandleBluetoothStatePacket(joystick, ctx, data, size);
405 break;
406 }
407 }
408
409 if (size < 0) {
410 /* Read error, device is disconnected */
411 HIDAPI_JoystickDisconnected(device, joystick->instance_id);
412 }
413 return (size >= 0);
414 }
415
416 static void
HIDAPI_DriverLuna_CloseJoystick(SDL_HIDAPI_Device * device,SDL_Joystick * joystick)417 HIDAPI_DriverLuna_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
418 {
419 SDL_LockMutex(device->dev_lock);
420 {
421 if (device->dev) {
422 SDL_hid_close(device->dev);
423 device->dev = NULL;
424 }
425
426 SDL_free(device->context);
427 device->context = NULL;
428 }
429 SDL_UnlockMutex(device->dev_lock);
430 }
431
432 static void
HIDAPI_DriverLuna_FreeDevice(SDL_HIDAPI_Device * device)433 HIDAPI_DriverLuna_FreeDevice(SDL_HIDAPI_Device *device)
434 {
435 }
436
437 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna =
438 {
439 SDL_HINT_JOYSTICK_HIDAPI_LUNA,
440 SDL_TRUE,
441 SDL_TRUE,
442 HIDAPI_DriverLuna_IsSupportedDevice,
443 HIDAPI_DriverLuna_GetDeviceName,
444 HIDAPI_DriverLuna_InitDevice,
445 HIDAPI_DriverLuna_GetDevicePlayerIndex,
446 HIDAPI_DriverLuna_SetDevicePlayerIndex,
447 HIDAPI_DriverLuna_UpdateDevice,
448 HIDAPI_DriverLuna_OpenJoystick,
449 HIDAPI_DriverLuna_RumbleJoystick,
450 HIDAPI_DriverLuna_RumbleJoystickTriggers,
451 HIDAPI_DriverLuna_GetJoystickCapabilities,
452 HIDAPI_DriverLuna_SetJoystickLED,
453 HIDAPI_DriverLuna_SendJoystickEffect,
454 HIDAPI_DriverLuna_SetJoystickSensorsEnabled,
455 HIDAPI_DriverLuna_CloseJoystick,
456 HIDAPI_DriverLuna_FreeDevice,
457 };
458
459 #endif /* SDL_JOYSTICK_HIDAPI_LUNA */
460
461 #endif /* SDL_JOYSTICK_HIDAPI */
462
463 /* vi: set ts=4 sw=4 expandtab: */
464