1 #ifndef INPUT_DINPUT_H_
2 #define INPUT_DINPUT_H_
3 
4 #include "input_common.h"
5 #include "modules/lib/osdlib.h"
6 
7 //============================================================
8 //  dinput_device - base directinput device
9 //============================================================
10 
11 // DirectInput-specific information about a device
12 struct dinput_api_state
13 {
14 #if DIRECTINPUT_VERSION >= 0x0800
15 	Microsoft::WRL::ComPtr<IDirectInputDevice8>  device;
16 #else
17 	Microsoft::WRL::ComPtr<IDirectInputDevice>   device;
18 	Microsoft::WRL::ComPtr<IDirectInputDevice2>  device2;
19 #endif
20 	DIDEVCAPS                                    caps;
21 	LPCDIDATAFORMAT                              format;
22 };
23 
24 class device_enum_interface
25 {
26 public:
27 	struct dinput_callback_context
28 	{
29 		device_enum_interface *     self;
30 		void *                      state;
31 	};
32 
~device_enum_interface()33 	virtual ~device_enum_interface()
34 	{
35 	}
36 
enum_callback(LPCDIDEVICEINSTANCE instance,LPVOID ref)37 	static BOOL CALLBACK enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref)
38 	{
39 		auto context = static_cast<dinput_callback_context*>(ref);
40 		return context->self->device_enum_callback(instance, context->state);
41 	}
42 
43 	virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) = 0;
44 };
45 
46 // Typedef for dynamically loaded function
47 #if DIRECTINPUT_VERSION >= 0x0800
48 typedef HRESULT (WINAPI *dinput_create_fn)(HINSTANCE, DWORD, LPDIRECTINPUT8 *, LPUNKNOWN);
49 #else
50 typedef HRESULT (WINAPI *dinput_create_fn)(HINSTANCE, DWORD, LPDIRECTINPUT *, LPUNKNOWN);
51 #endif
52 
53 enum class dinput_cooperative_level
54 {
55 	FOREGROUND,
56 	BACKGROUND
57 };
58 
59 class dinput_api_helper
60 {
61 private:
62 #if DIRECTINPUT_VERSION >= 0x0800
63 	Microsoft::WRL::ComPtr<IDirectInput8> m_dinput;
64 #else
65 	Microsoft::WRL::ComPtr<IDirectInput>  m_dinput;
66 #endif
67 	int                                   m_dinput_version;
68 	osd::dynamic_module::ptr              m_dinput_dll;
69 	dinput_create_fn                      m_dinput_create_prt;
70 
71 public:
72 	dinput_api_helper(int version);
73 	virtual ~dinput_api_helper();
74 	int initialize();
75 
76 	template<class TDevice>
create_device(running_machine & machine,input_module_base & module,LPCDIDEVICEINSTANCE instance,LPCDIDATAFORMAT format1,LPCDIDATAFORMAT format2,dinput_cooperative_level cooperative_level)77 	TDevice* create_device(
78 		running_machine &machine,
79 		input_module_base &module,
80 		LPCDIDEVICEINSTANCE instance,
81 		LPCDIDATAFORMAT format1,
82 		LPCDIDATAFORMAT format2,
83 		dinput_cooperative_level cooperative_level)
84 	{
85 		HRESULT result;
86 		std::shared_ptr<win_window_info> window;
87 		HWND hwnd;
88 
89 		// convert instance name to utf8
90 		std::string utf8_instance_name = osd::text::from_tstring(instance->tszInstanceName);
91 
92 		// set device id to name + product unique identifier + instance unique identifier
93 		std::string utf8_instance_id = utf8_instance_name + " product_" + guid_to_string(instance->guidProduct) + " instance_" + guid_to_string(instance->guidInstance);
94 
95 		// allocate memory for the device object
96 		TDevice* devinfo = module.devicelist()->create_device<TDevice>(machine, utf8_instance_name.c_str(), utf8_instance_id.c_str(), module);
97 
98 		// attempt to create a device
99 		result = m_dinput->CreateDevice(instance->guidInstance, devinfo->dinput.device.GetAddressOf(), nullptr);
100 		if (result != DI_OK)
101 			goto error;
102 
103 #if DIRECTINPUT_VERSION < 0x0800
104 		// try to get a version 2 device for it so we can use the poll method
105 		result = devinfo->dinput.device.CopyTo(IID_IDirectInputDevice2, reinterpret_cast<void**>(devinfo->dinput.device2.GetAddressOf()));
106 		if (result != DI_OK)
107 			devinfo->dinput.device2 = nullptr;
108 #endif
109 
110 		// get the caps
111 		devinfo->dinput.caps.dwSize = sizeof(devinfo->dinput.caps);
112 		result = devinfo->dinput.device->GetCapabilities(&devinfo->dinput.caps);
113 		if (result != DI_OK)
114 			goto error;
115 
116 		// attempt to set the data format
117 		devinfo->dinput.format = format1;
118 		result = devinfo->dinput.device->SetDataFormat(devinfo->dinput.format);
119 		if (result != DI_OK)
120 		{
121 			// use the secondary format if available
122 			if (format2 != nullptr)
123 			{
124 				devinfo->dinput.format = format2;
125 				result = devinfo->dinput.device->SetDataFormat(devinfo->dinput.format);
126 			}
127 			if (result != DI_OK)
128 				goto error;
129 		}
130 
131 		// default window to the first window in the list
132 		window = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front());
133 		DWORD di_cooperative_level;
134 		if (window->attached_mode())
135 		{
136 			// in attached mode we have to ignore the caller and hook up to the desktop window
137 			hwnd = GetDesktopWindow();
138 			di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
139 		}
140 		else
141 		{
142 			hwnd = window->platform_window();
143 			switch (cooperative_level)
144 			{
145 			case dinput_cooperative_level::BACKGROUND:
146 				di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
147 				break;
148 			case dinput_cooperative_level::FOREGROUND:
149 				di_cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
150 				break;
151 			default:
152 				throw false;
153 			}
154 		}
155 
156 		// set the cooperative level
157 		result = devinfo->dinput.device->SetCooperativeLevel(hwnd, di_cooperative_level);
158 		if (result != DI_OK)
159 			goto error;
160 
161 		return devinfo;
162 
163 	error:
164 		module.devicelist()->free_device(devinfo);
165 		return nullptr;
166 	}
167 
168 	HRESULT enum_attached_devices(int devclass, device_enum_interface *enumerate_interface, void *state) const;
169 
guid_to_string(const GUID & guid)170 	static std::string guid_to_string(const GUID& guid)
171 	{
172 		// Size of a GUID string with dashes plus null terminator
173 		char guid_string[37];
174 
175 		snprintf(
176 			guid_string, ARRAY_LENGTH(guid_string),
177 			"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
178 			guid.Data1, guid.Data2, guid.Data3,
179 			guid.Data4[0], guid.Data4[1], guid.Data4[2],
180 			guid.Data4[3], guid.Data4[4], guid.Data4[5],
181 			guid.Data4[6], guid.Data4[7]);
182 
183 		return guid_string;
184 	}
185 };
186 
187 class dinput_device : public device_info
188 {
189 public:
190 	dinput_api_state dinput;
191 
192 	dinput_device(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module);
193 	virtual ~dinput_device();
194 
195 protected:
196 	HRESULT poll_dinput(LPVOID pState) const;
197 };
198 
199 class dinput_keyboard_device : public dinput_device
200 {
201 private:
202 	std::mutex m_device_lock;
203 
204 public:
205 	keyboard_state  keyboard;
206 
207 	dinput_keyboard_device(running_machine &machine, const char *name, const char *id, input_module &module);
208 
209 	void poll() override;
210 	void reset() override;
211 };
212 
213 class dinput_mouse_device : public dinput_device
214 {
215 public:
216 	mouse_state mouse;
217 
218 public:
219 	dinput_mouse_device(running_machine &machine, const char *name, const char *id, input_module &module);
220 	void poll() override;
221 	void reset() override;
222 };
223 
224 // state information for a joystick; DirectInput state must be first element
225 struct dinput_joystick_state
226 {
227 	DIJOYSTATE              state;
228 	LONG                    rangemin[8];
229 	LONG                    rangemax[8];
230 };
231 
232 class dinput_joystick_device : public dinput_device
233 {
234 public:
235 	dinput_joystick_state   joystick;
236 public:
237 	dinput_joystick_device(running_machine &machine, const char *name, const char *id, input_module &module);
238 	void reset() override;
239 	void poll() override;
240 	int configure();
241 };
242 
243 
244 #endif
245