2 * Plug and Play support for hid devices found through SDL2
4 * Copyright 2017 CodeWeavers, Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
30 #ifdef HAVE_SDL2_SDL_H
31 # include <SDL2/SDL.h>
34 #define NONAMELESSUNION
37 #define WIN32_NO_STATUS
43 #include "ddk/hidtypes.h"
44 #include "wine/library.h"
45 #include "wine/debug.h"
46 #include "wine/unicode.h"
48 #include "controller.h"
50 #ifdef WORDS_BIGENDIAN
51 # define LE_WORD(x) RtlUshortByteSwap(x)
53 # define LE_WORD(x) (x)
58 WINE_DEFAULT_DEBUG_CHANNEL(plugplay
);
62 #define VID_MICROSOFT 0x045e
64 static const WORD PID_XBOX_CONTROLLERS
[] = {
65 0x0202, /* Xbox Controller */
66 0x0285, /* Xbox Controller S */
67 0x0289, /* Xbox Controller S */
68 0x028e, /* Xbox360 Controller */
69 0x028f, /* Xbox360 Wireless Controller */
70 0x02d1, /* Xbox One Controller */
71 0x02dd, /* Xbox One Controller (Covert Forces/Firmware 2015) */
72 0x02e0, /* Xbox One X Controller */
73 0x02e3, /* Xbox One Elite Controller */
74 0x02e6, /* Wireless XBox Controller Dongle */
75 0x02ea, /* Xbox One S Controller */
76 0x02fd, /* Xbox One S Controller (Firmware 2017) */
77 0x0719, /* Xbox 360 Wireless Adapter */
80 WINE_DECLARE_DEBUG_CHANNEL(hid_report
);
82 static DRIVER_OBJECT
*sdl_driver_obj
= NULL
;
84 static const WCHAR sdl_busidW
[] = {'S','D','L','J','O','Y',0};
86 static DWORD map_controllers
= 0;
89 DEFINE_GUID(GUID_DEVCLASS_SDL
, 0x463d60b5,0x802b,0x4bb2,0x8f,0xdb,0x7d,0xa9,0xb9,0x96,0x04,0xd8);
91 static void *sdl_handle
= NULL
;
94 #define MAKE_FUNCPTR(f) static typeof(f) * p##f = NULL
95 MAKE_FUNCPTR(SDL_GetError
);
96 MAKE_FUNCPTR(SDL_Init
);
97 MAKE_FUNCPTR(SDL_JoystickEventState
);
98 MAKE_FUNCPTR(SDL_JoystickGetGUID
);
99 MAKE_FUNCPTR(SDL_JoystickGetGUIDString
);
100 MAKE_FUNCPTR(SDL_JoystickInstanceID
);
101 MAKE_FUNCPTR(SDL_JoystickName
);
102 MAKE_FUNCPTR(SDL_JoystickNumAxes
);
103 MAKE_FUNCPTR(SDL_JoystickOpen
);
104 MAKE_FUNCPTR(SDL_WaitEvent
);
105 MAKE_FUNCPTR(SDL_JoystickNumButtons
);
106 MAKE_FUNCPTR(SDL_JoystickNumBalls
);
107 MAKE_FUNCPTR(SDL_JoystickNumHats
);
108 MAKE_FUNCPTR(SDL_JoystickGetAxis
);
109 MAKE_FUNCPTR(SDL_JoystickGetHat
);
110 MAKE_FUNCPTR(SDL_IsGameController
);
111 MAKE_FUNCPTR(SDL_GameControllerGetAxis
);
112 MAKE_FUNCPTR(SDL_GameControllerName
);
113 MAKE_FUNCPTR(SDL_GameControllerOpen
);
114 MAKE_FUNCPTR(SDL_GameControllerEventState
);
115 MAKE_FUNCPTR(SDL_HapticClose
);
116 MAKE_FUNCPTR(SDL_HapticDestroyEffect
);
117 MAKE_FUNCPTR(SDL_HapticNewEffect
);
118 MAKE_FUNCPTR(SDL_HapticOpenFromJoystick
);
119 MAKE_FUNCPTR(SDL_HapticQuery
);
120 MAKE_FUNCPTR(SDL_HapticRumbleInit
);
121 MAKE_FUNCPTR(SDL_HapticRumblePlay
);
122 MAKE_FUNCPTR(SDL_HapticRumbleSupported
);
123 MAKE_FUNCPTR(SDL_HapticRunEffect
);
124 MAKE_FUNCPTR(SDL_HapticStopAll
);
125 MAKE_FUNCPTR(SDL_JoystickIsHaptic
);
126 MAKE_FUNCPTR(SDL_memset
);
128 static Uint16 (*pSDL_JoystickGetProduct
)(SDL_Joystick
* joystick
);
129 static Uint16 (*pSDL_JoystickGetProductVersion
)(SDL_Joystick
* joystick
);
130 static Uint16 (*pSDL_JoystickGetVendor
)(SDL_Joystick
* joystick
);
132 struct platform_private
134 SDL_Joystick
*sdl_joystick
;
135 SDL_GameController
*sdl_controller
;
142 int report_descriptor_size
;
143 BYTE
*report_descriptor
;
148 SDL_Haptic
*sdl_haptic
;
149 int haptic_effect_id
;
152 static inline struct platform_private
*impl_from_DEVICE_OBJECT(DEVICE_OBJECT
*device
)
154 return (struct platform_private
*)get_platform_private(device
);
157 static const BYTE REPORT_AXIS_TAIL
[] = {
158 0x16, 0x00, 0x80, /* LOGICAL_MINIMUM (-32768) */
159 0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (32767) */
160 0x36, 0x00, 0x80, /* PHYSICAL_MINIMUM (-32768) */
161 0x46, 0xff, 0x7f, /* PHYSICAL_MAXIMUM (32767) */
162 0x75, 0x10, /* REPORT_SIZE (16) */
163 0x95, 0x00, /* REPORT_COUNT (?) */
164 0x81, 0x02, /* INPUT (Data,Var,Abs) */
166 #define IDX_ABS_AXIS_COUNT 15
168 static const BYTE CONTROLLER_BUTTONS
[] = {
169 0x05, 0x09, /* USAGE_PAGE (Button) */
170 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
171 0x29, 0x0f, /* USAGE_MAXIMUM (Button 15) */
172 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
173 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
174 0x35, 0x00, /* LOGICAL_MINIMUM (0) */
175 0x45, 0x01, /* LOGICAL_MAXIMUM (1) */
176 0x95, 0x0f, /* REPORT_COUNT (15) */
177 0x75, 0x01, /* REPORT_SIZE (1) */
178 0x81, 0x02, /* INPUT (Data,Var,Abs) */
180 0x95, 0x01, /* REPORT_COUNT (1) */
181 0x75, 0x01, /* REPORT_SIZE (1) */
182 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
185 static const BYTE CONTROLLER_AXIS
[] = {
186 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
187 0x09, 0x30, /* USAGE (X) */
188 0x09, 0x31, /* USAGE (Y) */
189 0x09, 0x33, /* USAGE (RX) */
190 0x09, 0x34, /* USAGE (RY) */
191 0x16, 0x00, 0x80, /* LOGICAL_MINIMUM (-32768) */
192 0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (32767) */
193 0x36, 0x00, 0x80, /* PHYSICAL_MINIMUM (-32768) */
194 0x46, 0xff, 0x7f, /* PHYSICAL_MAXIMUM (32767) */
195 0x75, 0x10, /* REPORT_SIZE (16) */
196 0x95, 0x04, /* REPORT_COUNT (4) */
197 0x81, 0x02, /* INPUT (Data,Var,Abs) */
200 static const BYTE CONTROLLER_TRIGGERS
[] = {
201 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
202 0x09, 0x32, /* USAGE (Z) */
203 0x09, 0x35, /* USAGE (RZ) */
204 0x16, 0x00, 0x00, /* LOGICAL_MINIMUM (0) */
205 0x26, 0xff, 0x7f, /* LOGICAL_MAXIMUM (32767) */
206 0x36, 0x00, 0x00, /* PHYSICAL_MINIMUM (0) */
207 0x46, 0xff, 0x7f, /* PHYSICAL_MAXIMUM (32767) */
208 0x75, 0x10, /* REPORT_SIZE (16) */
209 0x95, 0x02, /* REPORT_COUNT (2) */
210 0x81, 0x02, /* INPUT (Data,Var,Abs) */
213 static const BYTE HAPTIC_RUMBLE
[] = {
214 0x06, 0x00, 0xff, /* USAGE PAGE (vendor-defined) */
215 0x09, 0x01, /* USAGE (1) */
216 0x85, 0x00, /* REPORT_ID (0) */
218 0x95, 0x02, /* REPORT_COUNT (2) */
219 0x75, 0x08, /* REPORT_SIZE (8) */
220 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
222 0x15, 0x00, /* LOGICAL MINIMUM (0) */
223 0x25, 0xff, /* LOGICAL MAXIMUM (255) */
224 0x35, 0x00, /* PHYSICAL MINIMUM (0) */
225 0x45, 0xff, /* PHYSICAL MAXIMUM (255) */
226 0x75, 0x08, /* REPORT_SIZE (8) */
227 0x95, 0x02, /* REPORT_COUNT (2) */
228 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
230 0x95, 0x02, /* REPORT_COUNT (3) */
231 0x75, 0x08, /* REPORT_SIZE (8) */
232 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
235 static BYTE
*add_axis_block(BYTE
*report_ptr
, BYTE count
, BYTE page
, const BYTE
*usages
, BOOL absolute
)
238 memcpy(report_ptr
, REPORT_AXIS_HEADER
, sizeof(REPORT_AXIS_HEADER
));
239 report_ptr
[IDX_AXIS_PAGE
] = page
;
240 report_ptr
+= sizeof(REPORT_AXIS_HEADER
);
241 for (i
= 0; i
< count
; i
++)
243 memcpy(report_ptr
, REPORT_AXIS_USAGE
, sizeof(REPORT_AXIS_USAGE
));
244 report_ptr
[IDX_AXIS_USAGE
] = usages
[i
];
245 report_ptr
+= sizeof(REPORT_AXIS_USAGE
);
249 memcpy(report_ptr
, REPORT_AXIS_TAIL
, sizeof(REPORT_AXIS_TAIL
));
250 report_ptr
[IDX_ABS_AXIS_COUNT
] = count
;
251 report_ptr
+= sizeof(REPORT_AXIS_TAIL
);
255 memcpy(report_ptr
, REPORT_REL_AXIS_TAIL
, sizeof(REPORT_REL_AXIS_TAIL
));
256 report_ptr
[IDX_REL_AXIS_COUNT
] = count
;
257 report_ptr
+= sizeof(REPORT_REL_AXIS_TAIL
);
262 static void set_axis_value(struct platform_private
*ext
, int index
, short value
)
265 offset
= ext
->axis_start
+ index
* 2;
266 *((WORD
*)&ext
->report_buffer
[offset
]) = LE_WORD(value
);
269 static void set_ball_value(struct platform_private
*ext
, int index
, int value1
, int value2
)
272 offset
= ext
->ball_start
+ (index
* 2);
273 if (value1
> 127) value1
= 127;
274 if (value1
< -127) value1
= -127;
275 if (value2
> 127) value2
= 127;
276 if (value2
< -127) value2
= -127;
277 ext
->report_buffer
[offset
] = value1
;
278 ext
->report_buffer
[offset
+ 1] = value2
;
281 static void set_hat_value(struct platform_private
*ext
, int index
, int value
)
284 offset
= ext
->hat_start
+ index
;
287 case SDL_HAT_CENTERED
: ext
->report_buffer
[offset
] = 8; break;
288 case SDL_HAT_UP
: ext
->report_buffer
[offset
] = 0; break;
289 case SDL_HAT_RIGHTUP
: ext
->report_buffer
[offset
] = 1; break;
290 case SDL_HAT_RIGHT
: ext
->report_buffer
[offset
] = 2; break;
291 case SDL_HAT_RIGHTDOWN
: ext
->report_buffer
[offset
] = 3; break;
292 case SDL_HAT_DOWN
: ext
->report_buffer
[offset
] = 4; break;
293 case SDL_HAT_LEFTDOWN
: ext
->report_buffer
[offset
] = 5; break;
294 case SDL_HAT_LEFT
: ext
->report_buffer
[offset
] = 6; break;
295 case SDL_HAT_LEFTUP
: ext
->report_buffer
[offset
] = 7; break;
299 static int test_haptic(struct platform_private
*ext
)
302 if (pSDL_JoystickIsHaptic(ext
->sdl_joystick
))
304 ext
->sdl_haptic
= pSDL_HapticOpenFromJoystick(ext
->sdl_joystick
);
305 if (ext
->sdl_haptic
&&
306 ((pSDL_HapticQuery(ext
->sdl_haptic
) & SDL_HAPTIC_LEFTRIGHT
) != 0 ||
307 pSDL_HapticRumbleSupported(ext
->sdl_haptic
)))
309 pSDL_HapticStopAll(ext
->sdl_haptic
);
310 pSDL_HapticRumbleInit(ext
->sdl_haptic
);
311 rc
= sizeof(HAPTIC_RUMBLE
);
312 ext
->haptic_effect_id
= -1;
316 pSDL_HapticClose(ext
->sdl_haptic
);
317 ext
->sdl_haptic
= NULL
;
323 static int build_haptic(struct platform_private
*ext
, BYTE
*report_ptr
)
327 memcpy(report_ptr
, HAPTIC_RUMBLE
, sizeof(HAPTIC_RUMBLE
));
328 return (sizeof(HAPTIC_RUMBLE
));
333 static BOOL
build_report_descriptor(struct platform_private
*ext
)
336 INT i
, descript_size
;
338 INT button_count
, axis_count
, ball_count
, hat_count
;
339 static const BYTE device_usage
[2] = {HID_USAGE_PAGE_GENERIC
, HID_USAGE_GENERIC_GAMEPAD
};
340 static const BYTE controller_usages
[] = {
344 HID_USAGE_GENERIC_RX
,
345 HID_USAGE_GENERIC_RY
,
346 HID_USAGE_GENERIC_RZ
,
347 HID_USAGE_GENERIC_SLIDER
,
348 HID_USAGE_GENERIC_DIAL
,
349 HID_USAGE_GENERIC_WHEEL
};
350 static const BYTE joystick_usages
[] = {
354 HID_USAGE_GENERIC_RZ
,
355 HID_USAGE_GENERIC_RX
,
356 HID_USAGE_GENERIC_RY
,
357 HID_USAGE_GENERIC_SLIDER
,
358 HID_USAGE_GENERIC_DIAL
,
359 HID_USAGE_GENERIC_WHEEL
};
361 descript_size
= sizeof(REPORT_HEADER
) + sizeof(REPORT_TAIL
);
364 /* For now lump all buttons just into incremental usages, Ignore Keys */
365 button_count
= pSDL_JoystickNumButtons(ext
->sdl_joystick
);
368 descript_size
+= sizeof(REPORT_BUTTONS
);
369 if (button_count
% 8)
370 descript_size
+= sizeof(REPORT_PADDING
);
371 report_size
= (button_count
+ 7) / 8;
374 axis_count
= pSDL_JoystickNumAxes(ext
->sdl_joystick
);
377 FIXME("Clamping joystick to 6 axis\n");
381 ext
->axis_start
= report_size
;
384 descript_size
+= sizeof(REPORT_AXIS_HEADER
);
385 descript_size
+= (sizeof(REPORT_AXIS_USAGE
) * axis_count
);
386 descript_size
+= sizeof(REPORT_AXIS_TAIL
);
387 report_size
+= (2 * axis_count
);
390 ball_count
= pSDL_JoystickNumBalls(ext
->sdl_joystick
);
391 ext
->ball_start
= report_size
;
394 if ((ball_count
*2) + axis_count
> 9)
396 FIXME("Capping ball + axis at 9\n");
397 ball_count
= (9-axis_count
)/2;
399 descript_size
+= sizeof(REPORT_AXIS_HEADER
);
400 descript_size
+= (sizeof(REPORT_AXIS_USAGE
) * ball_count
* 2);
401 descript_size
+= sizeof(REPORT_REL_AXIS_TAIL
);
402 report_size
+= (2*ball_count
);
405 hat_count
= pSDL_JoystickNumHats(ext
->sdl_joystick
);
406 ext
->hat_start
= report_size
;
409 descript_size
+= sizeof(REPORT_HATSWITCH
);
410 for (i
= 0; i
< hat_count
; i
++)
414 descript_size
+= test_haptic(ext
);
416 TRACE("Report Descriptor will be %i bytes\n", descript_size
);
417 TRACE("Report will be %i bytes\n", report_size
);
419 ext
->report_descriptor
= HeapAlloc(GetProcessHeap(), 0, descript_size
);
420 if (!ext
->report_descriptor
)
422 ERR("Failed to alloc report descriptor\n");
425 report_ptr
= ext
->report_descriptor
;
427 memcpy(report_ptr
, REPORT_HEADER
, sizeof(REPORT_HEADER
));
428 report_ptr
[IDX_HEADER_PAGE
] = device_usage
[0];
429 report_ptr
[IDX_HEADER_USAGE
] = device_usage
[1];
430 report_ptr
+= sizeof(REPORT_HEADER
);
433 report_ptr
= add_button_block(report_ptr
, 1, button_count
);
434 if (button_count
% 8)
436 BYTE padding
= 8 - (button_count
% 8);
437 report_ptr
= add_padding_block(report_ptr
, padding
);
442 if (axis_count
== 6 && button_count
>= 14)
443 report_ptr
= add_axis_block(report_ptr
, axis_count
, HID_USAGE_PAGE_GENERIC
, controller_usages
, TRUE
);
445 report_ptr
= add_axis_block(report_ptr
, axis_count
, HID_USAGE_PAGE_GENERIC
, joystick_usages
, TRUE
);
450 report_ptr
= add_axis_block(report_ptr
, ball_count
* 2, HID_USAGE_PAGE_GENERIC
, &joystick_usages
[axis_count
], FALSE
);
453 report_ptr
= add_hatswitch(report_ptr
, hat_count
);
455 report_ptr
+= build_haptic(ext
, report_ptr
);
456 memcpy(report_ptr
, REPORT_TAIL
, sizeof(REPORT_TAIL
));
458 ext
->report_descriptor_size
= descript_size
;
459 ext
->buffer_length
= report_size
;
460 ext
->report_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, report_size
);
461 if (ext
->report_buffer
== NULL
)
463 ERR("Failed to alloc report buffer\n");
464 HeapFree(GetProcessHeap(), 0, ext
->report_descriptor
);
468 /* Initialize axis in the report */
469 for (i
= 0; i
< axis_count
; i
++)
470 set_axis_value(ext
, i
, pSDL_JoystickGetAxis(ext
->sdl_joystick
, i
));
471 for (i
= 0; i
< hat_count
; i
++)
472 set_hat_value(ext
, i
, pSDL_JoystickGetHat(ext
->sdl_joystick
, i
));
477 static BOOL
build_mapped_report_descriptor(struct platform_private
*ext
)
480 INT i
, descript_size
;
482 descript_size
= sizeof(REPORT_HEADER
) + sizeof(REPORT_TAIL
);
483 descript_size
+= sizeof(CONTROLLER_BUTTONS
);
484 descript_size
+= sizeof(CONTROLLER_AXIS
);
485 descript_size
+= sizeof(CONTROLLER_TRIGGERS
);
486 descript_size
+= test_haptic(ext
);
489 ext
->buffer_length
= 14;
491 TRACE("Report Descriptor will be %i bytes\n", descript_size
);
492 TRACE("Report will be %i bytes\n", ext
->buffer_length
);
494 ext
->report_descriptor
= HeapAlloc(GetProcessHeap(), 0, descript_size
);
495 if (!ext
->report_descriptor
)
497 ERR("Failed to alloc report descriptor\n");
500 report_ptr
= ext
->report_descriptor
;
502 memcpy(report_ptr
, REPORT_HEADER
, sizeof(REPORT_HEADER
));
503 report_ptr
[IDX_HEADER_PAGE
] = HID_USAGE_PAGE_GENERIC
;
504 report_ptr
[IDX_HEADER_USAGE
] = HID_USAGE_GENERIC_GAMEPAD
;
505 report_ptr
+= sizeof(REPORT_HEADER
);
506 memcpy(report_ptr
, CONTROLLER_BUTTONS
, sizeof(CONTROLLER_BUTTONS
));
507 report_ptr
+= sizeof(CONTROLLER_BUTTONS
);
508 memcpy(report_ptr
, CONTROLLER_AXIS
, sizeof(CONTROLLER_AXIS
));
509 report_ptr
+= sizeof(CONTROLLER_AXIS
);
510 memcpy(report_ptr
, CONTROLLER_TRIGGERS
, sizeof(CONTROLLER_TRIGGERS
));
511 report_ptr
+= sizeof(CONTROLLER_TRIGGERS
);
512 report_ptr
+= build_haptic(ext
, report_ptr
);
513 memcpy(report_ptr
, REPORT_TAIL
, sizeof(REPORT_TAIL
));
515 ext
->report_descriptor_size
= descript_size
;
516 ext
->report_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, ext
->buffer_length
);
517 if (ext
->report_buffer
== NULL
)
519 ERR("Failed to alloc report buffer\n");
520 HeapFree(GetProcessHeap(), 0, ext
->report_descriptor
);
524 /* Initialize axis in the report */
525 for (i
= SDL_CONTROLLER_AXIS_LEFTX
; i
< SDL_CONTROLLER_AXIS_MAX
; i
++)
526 set_axis_value(ext
, i
, pSDL_GameControllerGetAxis(ext
->sdl_controller
, i
));
531 static int compare_platform_device(DEVICE_OBJECT
*device
, void *platform_dev
)
533 SDL_JoystickID id1
= impl_from_DEVICE_OBJECT(device
)->id
;
534 SDL_JoystickID id2
= PtrToUlong(platform_dev
);
538 static NTSTATUS
get_reportdescriptor(DEVICE_OBJECT
*device
, BYTE
*buffer
, DWORD length
, DWORD
*out_length
)
540 struct platform_private
*ext
= impl_from_DEVICE_OBJECT(device
);
542 *out_length
= ext
->report_descriptor_size
;
544 if (length
< ext
->report_descriptor_size
)
545 return STATUS_BUFFER_TOO_SMALL
;
547 memcpy(buffer
, ext
->report_descriptor
, ext
->report_descriptor_size
);
549 return STATUS_SUCCESS
;
552 static NTSTATUS
get_string(DEVICE_OBJECT
*device
, DWORD index
, WCHAR
*buffer
, DWORD length
)
554 struct platform_private
*ext
= impl_from_DEVICE_OBJECT(device
);
555 const char* str
= NULL
;
559 case HID_STRING_ID_IPRODUCT
:
560 if (ext
->sdl_controller
)
561 str
= pSDL_GameControllerName(ext
->sdl_controller
);
563 str
= pSDL_JoystickName(ext
->sdl_joystick
);
565 case HID_STRING_ID_IMANUFACTURER
:
568 case HID_STRING_ID_ISERIALNUMBER
:
572 ERR("Unhandled string index %i\n", index
);
576 MultiByteToWideChar(CP_ACP
, 0, str
, -1, buffer
, length
);
580 return STATUS_SUCCESS
;
583 static NTSTATUS
begin_report_processing(DEVICE_OBJECT
*device
)
585 return STATUS_SUCCESS
;
588 static NTSTATUS
set_output_report(DEVICE_OBJECT
*device
, UCHAR id
, BYTE
*report
, DWORD length
, ULONG_PTR
*written
)
590 struct platform_private
*ext
= impl_from_DEVICE_OBJECT(device
);
592 if (ext
->sdl_haptic
&& id
== 0)
594 WORD left
= report
[2] * 128;
595 WORD right
= report
[3] * 128;
597 if (ext
->haptic_effect_id
>= 0)
599 pSDL_HapticDestroyEffect(ext
->sdl_haptic
, ext
->haptic_effect_id
);
600 ext
->haptic_effect_id
= -1;
602 pSDL_HapticStopAll(ext
->sdl_haptic
);
603 if (left
!= 0 || right
!= 0)
605 SDL_HapticEffect effect
;
607 pSDL_memset( &effect
, 0, sizeof(SDL_HapticEffect
) );
608 effect
.type
= SDL_HAPTIC_LEFTRIGHT
;
609 effect
.leftright
.length
= -1;
610 effect
.leftright
.large_magnitude
= left
;
611 effect
.leftright
.small_magnitude
= right
;
613 ext
->haptic_effect_id
= pSDL_HapticNewEffect(ext
->sdl_haptic
, &effect
);
614 if (ext
->haptic_effect_id
>= 0)
616 pSDL_HapticRunEffect(ext
->sdl_haptic
, ext
->haptic_effect_id
, 1);
620 float i
= (float)((left
+ right
)/2.0) / 32767.0;
621 pSDL_HapticRumblePlay(ext
->sdl_haptic
, i
, -1);
625 return STATUS_SUCCESS
;
630 return STATUS_NOT_IMPLEMENTED
;
634 static NTSTATUS
get_feature_report(DEVICE_OBJECT
*device
, UCHAR id
, BYTE
*report
, DWORD length
, ULONG_PTR
*read
)
637 return STATUS_NOT_IMPLEMENTED
;
640 static NTSTATUS
set_feature_report(DEVICE_OBJECT
*device
, UCHAR id
, BYTE
*report
, DWORD length
, ULONG_PTR
*written
)
643 return STATUS_NOT_IMPLEMENTED
;
646 static const platform_vtbl sdl_vtbl
=
648 compare_platform_device
,
649 get_reportdescriptor
,
651 begin_report_processing
,
657 static BOOL
set_report_from_event(SDL_Event
*event
)
659 DEVICE_OBJECT
*device
;
660 struct platform_private
*private;
661 /* All the events coming in will have 'which' as a 3rd field */
662 SDL_JoystickID index
= ((SDL_JoyButtonEvent
*)event
)->which
;
664 device
= bus_find_hid_device(&sdl_vtbl
, ULongToPtr(index
));
667 ERR("Failed to find device at index %i\n",index
);
670 private = impl_from_DEVICE_OBJECT(device
);
671 if (private->sdl_controller
)
673 /* We want mapped events */
679 case SDL_JOYBUTTONDOWN
:
680 case SDL_JOYBUTTONUP
:
682 SDL_JoyButtonEvent
*ie
= &event
->jbutton
;
684 set_button_value(ie
->button
, ie
->state
, private->report_buffer
);
686 process_hid_report(device
, private->report_buffer
, private->buffer_length
);
689 case SDL_JOYAXISMOTION
:
691 SDL_JoyAxisEvent
*ie
= &event
->jaxis
;
695 set_axis_value(private, ie
->axis
, ie
->value
);
696 process_hid_report(device
, private->report_buffer
, private->buffer_length
);
700 case SDL_JOYBALLMOTION
:
702 SDL_JoyBallEvent
*ie
= &event
->jball
;
704 set_ball_value(private, ie
->ball
, ie
->xrel
, ie
->yrel
);
705 process_hid_report(device
, private->report_buffer
, private->buffer_length
);
708 case SDL_JOYHATMOTION
:
710 SDL_JoyHatEvent
*ie
= &event
->jhat
;
712 set_hat_value(private, ie
->hat
, ie
->value
);
713 process_hid_report(device
, private->report_buffer
, private->buffer_length
);
717 ERR("TODO: Process Report (0x%x)\n",event
->type
);
722 static BOOL
set_mapped_report_from_event(SDL_Event
*event
)
724 DEVICE_OBJECT
*device
;
725 struct platform_private
*private;
726 /* All the events coming in will have 'which' as a 3rd field */
727 int index
= ((SDL_ControllerButtonEvent
*)event
)->which
;
728 device
= bus_find_hid_device(&sdl_vtbl
, ULongToPtr(index
));
731 ERR("Failed to find device at index %i\n",index
);
734 private = impl_from_DEVICE_OBJECT(device
);
738 case SDL_CONTROLLERBUTTONDOWN
:
739 case SDL_CONTROLLERBUTTONUP
:
742 SDL_ControllerButtonEvent
*ie
= &event
->cbutton
;
746 case SDL_CONTROLLER_BUTTON_A
: usage
= 0; break;
747 case SDL_CONTROLLER_BUTTON_B
: usage
= 1; break;
748 case SDL_CONTROLLER_BUTTON_X
: usage
= 2; break;
749 case SDL_CONTROLLER_BUTTON_Y
: usage
= 3; break;
750 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER
: usage
= 4; break;
751 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
: usage
= 5; break;
752 case SDL_CONTROLLER_BUTTON_LEFTSTICK
: usage
= 6; break;
753 case SDL_CONTROLLER_BUTTON_RIGHTSTICK
: usage
= 7; break;
754 case SDL_CONTROLLER_BUTTON_START
: usage
= 8; break;
755 case SDL_CONTROLLER_BUTTON_BACK
: usage
= 9; break;
756 case SDL_CONTROLLER_BUTTON_GUIDE
: usage
= 10; break;
757 case SDL_CONTROLLER_BUTTON_DPAD_UP
: usage
= 11; break;
758 case SDL_CONTROLLER_BUTTON_DPAD_DOWN
: usage
= 12; break;
759 case SDL_CONTROLLER_BUTTON_DPAD_LEFT
: usage
= 13; break;
760 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT
: usage
= 14; break;
762 ERR("Unknown Button %i\n",ie
->button
);
767 set_button_value(usage
, ie
->state
, private->report_buffer
);
768 process_hid_report(device
, private->report_buffer
, private->buffer_length
);
772 case SDL_CONTROLLERAXISMOTION
:
774 SDL_ControllerAxisEvent
*ie
= &event
->caxis
;
776 set_axis_value(private, ie
->axis
, ie
->value
);
777 process_hid_report(device
, private->report_buffer
, private->buffer_length
);
781 ERR("TODO: Process Report (%x)\n",event
->type
);
786 static void try_remove_device(SDL_JoystickID index
)
788 DEVICE_OBJECT
*device
= NULL
;
790 device
= bus_find_hid_device(&sdl_vtbl
, ULongToPtr(index
));
793 IoInvalidateDeviceRelations(device
, RemovalRelations
);
795 bus_remove_hid_device(device
);
798 static void try_add_device(SDL_JoystickID index
)
800 DWORD vid
= 0, pid
= 0, version
= 0;
801 DEVICE_OBJECT
*device
= NULL
;
802 WCHAR serial
[34] = {0};
804 BOOL is_xbox_gamepad
;
806 SDL_Joystick
* joystick
;
808 SDL_JoystickGUID guid
;
809 SDL_GameController
*controller
= NULL
;
811 if ((joystick
= pSDL_JoystickOpen(index
)) == NULL
)
813 WARN("Unable to open sdl device %i: %s\n", index
, pSDL_GetError());
817 if (map_controllers
&& pSDL_IsGameController(index
))
818 controller
= pSDL_GameControllerOpen(index
);
820 id
= pSDL_JoystickInstanceID(joystick
);
824 pid
= PID_XBOX_CONTROLLERS
[3];
829 if (pSDL_JoystickGetProductVersion
!= NULL
) {
830 vid
= pSDL_JoystickGetVendor(joystick
);
831 pid
= pSDL_JoystickGetProduct(joystick
);
832 version
= pSDL_JoystickGetProductVersion(joystick
);
837 pid
= pSDL_JoystickInstanceID(joystick
) + 1;
842 guid
= pSDL_JoystickGetGUID(joystick
);
843 pSDL_JoystickGetGUIDString(guid
, guid_str
, sizeof(guid_str
));
844 MultiByteToWideChar(CP_ACP
, 0, guid_str
, -1, serial
, sizeof(guid_str
));
848 TRACE("Found sdl game controller %i (vid %04x, pid %04x, version %u, serial %s)\n",
849 id
, vid
, pid
, version
, debugstr_w(serial
));
850 is_xbox_gamepad
= TRUE
;
854 int button_count
, axis_count
;
856 TRACE("Found sdl device %i (vid %04x, pid %04x, version %u, serial %s)\n",
857 id
, vid
, pid
, version
, debugstr_w(serial
));
859 axis_count
= pSDL_JoystickNumAxes(joystick
);
860 button_count
= pSDL_JoystickNumAxes(joystick
);
861 is_xbox_gamepad
= (axis_count
== 6 && button_count
>= 14);
864 device
= bus_create_hid_device(sdl_driver_obj
, sdl_busidW
, vid
, pid
, version
, id
, serial
, is_xbox_gamepad
, &GUID_DEVCLASS_SDL
, &sdl_vtbl
, sizeof(struct platform_private
));
869 struct platform_private
*private = impl_from_DEVICE_OBJECT(device
);
870 private->sdl_joystick
= joystick
;
871 private->sdl_controller
= controller
;
874 rc
= build_mapped_report_descriptor(private);
876 rc
= build_report_descriptor(private);
879 ERR("Building report descriptor failed, removing device\n");
880 bus_remove_hid_device(device
);
881 HeapFree(GetProcessHeap(), 0, serial
);
884 IoInvalidateDeviceRelations(device
, BusRelations
);
888 WARN("Ignoring device %i\n", id
);
892 static void process_device_event(SDL_Event
*event
)
894 TRACE_(hid_report
)("Received action %x\n", event
->type
);
896 if (event
->type
== SDL_JOYDEVICEADDED
)
897 try_add_device(((SDL_JoyDeviceEvent
*)event
)->which
);
898 else if (event
->type
== SDL_JOYDEVICEREMOVED
)
899 try_remove_device(((SDL_JoyDeviceEvent
*)event
)->which
);
900 else if (event
->type
>= SDL_JOYAXISMOTION
&& event
->type
<= SDL_JOYBUTTONUP
)
901 set_report_from_event(event
);
902 else if (event
->type
>= SDL_CONTROLLERAXISMOTION
&& event
->type
<= SDL_CONTROLLERBUTTONUP
)
903 set_mapped_report_from_event(event
);
906 static DWORD CALLBACK
deviceloop_thread(void *args
)
908 HANDLE init_done
= args
;
911 if (pSDL_Init(SDL_INIT_GAMECONTROLLER
|SDL_INIT_HAPTIC
) < 0)
913 ERR("Can't init SDL: %s\n", pSDL_GetError());
914 return STATUS_UNSUCCESSFUL
;
917 pSDL_JoystickEventState(SDL_ENABLE
);
918 pSDL_GameControllerEventState(SDL_ENABLE
);
923 while (pSDL_WaitEvent(&event
) != 0)
924 process_device_event(&event
);
926 TRACE("Device thread exiting\n");
930 void sdl_driver_unload( void )
932 TRACE("Unload Driver\n");
935 NTSTATUS WINAPI
sdl_driver_init(DRIVER_OBJECT
*driver
, UNICODE_STRING
*registry_path
)
937 static const WCHAR controller_modeW
[] = {'M','a','p',' ','C','o','n','t','r','o','l','l','e','r','s',0};
938 static const UNICODE_STRING controller_mode
= {sizeof(controller_modeW
) - sizeof(WCHAR
), sizeof(controller_modeW
), (WCHAR
*)controller_modeW
};
943 TRACE("(%p, %s)\n", driver
, debugstr_w(registry_path
->Buffer
));
944 if (sdl_handle
== NULL
)
946 sdl_handle
= wine_dlopen(SONAME_LIBSDL2
, RTLD_NOW
, NULL
, 0);
948 WARN("could not load %s\n", SONAME_LIBSDL2
);
949 sdl_driver_obj
= NULL
;
950 return STATUS_UNSUCCESSFUL
;
952 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(sdl_handle, #f, NULL, 0)) == NULL){WARN("Can't find symbol %s\n", #f); goto sym_not_found;}
953 LOAD_FUNCPTR(SDL_GetError
);
954 LOAD_FUNCPTR(SDL_Init
);
955 LOAD_FUNCPTR(SDL_JoystickEventState
);
956 LOAD_FUNCPTR(SDL_JoystickGetGUID
);
957 LOAD_FUNCPTR(SDL_JoystickGetGUIDString
);
958 LOAD_FUNCPTR(SDL_JoystickInstanceID
);
959 LOAD_FUNCPTR(SDL_JoystickName
);
960 LOAD_FUNCPTR(SDL_JoystickNumAxes
);
961 LOAD_FUNCPTR(SDL_JoystickOpen
);
962 LOAD_FUNCPTR(SDL_WaitEvent
);
963 LOAD_FUNCPTR(SDL_JoystickNumButtons
);
964 LOAD_FUNCPTR(SDL_JoystickNumBalls
);
965 LOAD_FUNCPTR(SDL_JoystickNumHats
);
966 LOAD_FUNCPTR(SDL_JoystickGetAxis
);
967 LOAD_FUNCPTR(SDL_JoystickGetHat
);
968 LOAD_FUNCPTR(SDL_IsGameController
);
969 LOAD_FUNCPTR(SDL_GameControllerGetAxis
);
970 LOAD_FUNCPTR(SDL_GameControllerName
);
971 LOAD_FUNCPTR(SDL_GameControllerOpen
);
972 LOAD_FUNCPTR(SDL_GameControllerEventState
);
973 LOAD_FUNCPTR(SDL_HapticClose
);
974 LOAD_FUNCPTR(SDL_HapticDestroyEffect
);
975 LOAD_FUNCPTR(SDL_HapticNewEffect
);
976 LOAD_FUNCPTR(SDL_HapticOpenFromJoystick
);
977 LOAD_FUNCPTR(SDL_HapticQuery
);
978 LOAD_FUNCPTR(SDL_HapticRumbleInit
);
979 LOAD_FUNCPTR(SDL_HapticRumblePlay
);
980 LOAD_FUNCPTR(SDL_HapticRumbleSupported
);
981 LOAD_FUNCPTR(SDL_HapticRunEffect
);
982 LOAD_FUNCPTR(SDL_HapticStopAll
);
983 LOAD_FUNCPTR(SDL_JoystickIsHaptic
);
984 LOAD_FUNCPTR(SDL_memset
);
986 pSDL_JoystickGetProduct
= wine_dlsym(sdl_handle
, "SDL_JoystickGetProduct", NULL
, 0);
987 pSDL_JoystickGetProductVersion
= wine_dlsym(sdl_handle
, "SDL_JoystickGetProductVersion", NULL
, 0);
988 pSDL_JoystickGetVendor
= wine_dlsym(sdl_handle
, "SDL_JoystickGetVendor", NULL
, 0);
991 sdl_driver_obj
= driver
;
992 driver
->MajorFunction
[IRP_MJ_PNP
] = common_pnp_dispatch
;
993 driver
->MajorFunction
[IRP_MJ_INTERNAL_DEVICE_CONTROL
] = hid_internal_dispatch
;
995 map_controllers
= check_bus_option(registry_path
, &controller_mode
, 1);
997 if (!(events
[0] = CreateEventW(NULL
, TRUE
, FALSE
, NULL
)))
999 if (!(events
[1] = CreateThread(NULL
, 0, deviceloop_thread
, events
[0], 0, NULL
)))
1001 CloseHandle(events
[0]);
1005 result
= WaitForMultipleObjects(2, events
, FALSE
, INFINITE
);
1006 CloseHandle(events
[0]);
1007 CloseHandle(events
[1]);
1008 if (result
== WAIT_OBJECT_0
)
1010 TRACE("Initialization successful\n");
1011 return STATUS_SUCCESS
;
1015 sdl_driver_obj
= NULL
;
1016 return STATUS_UNSUCCESSFUL
;
1018 wine_dlclose(sdl_handle
, NULL
, 0);
1020 return STATUS_UNSUCCESSFUL
;
1025 NTSTATUS WINAPI
sdl_driver_init(DRIVER_OBJECT
*driver
, UNICODE_STRING
*registry_path
)
1027 WARN("compiled without SDL support\n");
1028 return STATUS_NOT_IMPLEMENTED
;
1031 void sdl_driver_unload( void )
1033 TRACE("Stub: Unload Driver\n");
1036 #endif /* SONAME_LIBSDL2 */