1 /*************************************************************************/
2 /*  joystick.h                                                           */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 //author: Andreas Haas <hondres,  liugam3@gmail.com>
31 #ifndef JOYSTICK_H
32 #define JOYSTICK_H
33 
34 #include "os_windows.h"
35 #define DIRECTINPUT_VERSION 0x0800
36 #include <dinput.h>
37 #include <xinput.h> // on unix the file is called "xinput.h", on windows I'm sure it won't mind
38 
39 #ifndef SAFE_RELEASE // when Windows Media Device M? is not present
40 #define SAFE_RELEASE(x) \
41 	if (x != NULL) {    \
42 		x->Release();   \
43 		x = NULL;       \
44 	}
45 #endif
46 
47 #ifndef XUSER_MAX_COUNT
48 #define XUSER_MAX_COUNT 4
49 #endif
50 
51 class joystick_windows {
52 public:
53 	joystick_windows();
54 	joystick_windows(InputDefault *_input, HWND *hwnd);
55 	~joystick_windows();
56 
57 	void probe_joysticks();
58 	unsigned int process_joysticks(unsigned int p_last_id);
59 
60 private:
61 	enum {
62 		JOYSTICKS_MAX = 16,
63 		JOY_AXIS_COUNT = 6,
64 		MIN_JOY_AXIS = 10,
65 		MAX_JOY_AXIS = 32768,
66 		MAX_JOY_BUTTONS = 128,
67 		KEY_EVENT_BUFFER_SIZE = 512,
68 		MAX_TRIGGER = 255
69 	};
70 
71 	struct dinput_gamepad {
72 
73 		int id;
74 		bool attached;
75 		bool confirmed;
76 		bool last_buttons[MAX_JOY_BUTTONS];
77 		DWORD last_pad;
78 
79 		LPDIRECTINPUTDEVICE8 di_joy;
80 		List<DWORD> joy_axis;
81 		GUID guid;
82 
dinput_gamepaddinput_gamepad83 		dinput_gamepad() {
84 			id = -1;
85 			last_pad = -1;
86 			attached = false;
87 			confirmed = false;
88 
89 			for (int i = 0; i < MAX_JOY_BUTTONS; i++)
90 				last_buttons[i] = false;
91 		}
92 	};
93 
94 	struct xinput_gamepad {
95 
96 		int id;
97 		bool attached;
98 		bool vibrating;
99 		DWORD last_packet;
100 		XINPUT_STATE state;
101 		uint64_t ff_timestamp;
102 		uint64_t ff_end_timestamp;
103 
xinput_gamepadxinput_gamepad104 		xinput_gamepad() {
105 			attached = false;
106 			vibrating = false;
107 			ff_timestamp = 0;
108 			ff_end_timestamp = 0;
109 			last_packet = 0;
110 		}
111 	};
112 
113 	typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE *pState);
114 	typedef DWORD(WINAPI *XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration);
115 
116 	HWND *hWnd;
117 	HANDLE xinput_dll;
118 	LPDIRECTINPUT8 dinput;
119 	InputDefault *input;
120 
121 	int id_to_change;
122 	int joystick_count;
123 	bool attached_joysticks[JOYSTICKS_MAX];
124 	dinput_gamepad d_joysticks[JOYSTICKS_MAX];
125 	xinput_gamepad x_joysticks[XUSER_MAX_COUNT];
126 
127 	static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE *p_instance, void *p_context);
128 	static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context);
129 
130 	void setup_joystick_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id);
131 	void close_joystick(int id = -1);
132 	void load_xinput();
133 	void unload_xinput();
134 
135 	unsigned int post_hat(unsigned int p_last_id, int p_device, DWORD p_dpad);
136 
137 	bool have_device(const GUID &p_guid);
138 	bool is_xinput_device(const GUID *p_guid);
139 	bool setup_dinput_joystick(const DIDEVICEINSTANCE *instance);
140 	void joystick_vibration_start_xinput(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp);
141 	void joystick_vibration_stop_xinput(int p_device, uint64_t p_timestamp);
142 
143 	InputDefault::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
144 	XInputGetState_t xinput_get_state;
145 	XInputSetState_t xinput_set_state;
146 };
147 
148 #endif
149