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