| 
									
										
										
										
											2015-05-24 06:32:32 +02:00
										 |  |  | // Copyright 2010 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2+
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "InputCommon/ControllerInterface/XInput/XInput.h"
 | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-17 12:03:44 +01:00
										 |  |  | #ifndef XINPUT_GAMEPAD_GUIDE
 | 
					
						
							|  |  |  | #define XINPUT_GAMEPAD_GUIDE 0x0400
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | namespace ciface | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | namespace XInput | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-07-26 05:30:50 +00:00
										 |  |  | static const struct | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   const char* const name; | 
					
						
							|  |  |  |   const WORD bitmask; | 
					
						
							|  |  |  | } named_buttons[] = {{"Button A", XINPUT_GAMEPAD_A}, | 
					
						
							|  |  |  |                      {"Button B", XINPUT_GAMEPAD_B}, | 
					
						
							|  |  |  |                      {"Button X", XINPUT_GAMEPAD_X}, | 
					
						
							|  |  |  |                      {"Button Y", XINPUT_GAMEPAD_Y}, | 
					
						
							|  |  |  |                      {"Pad N", XINPUT_GAMEPAD_DPAD_UP}, | 
					
						
							|  |  |  |                      {"Pad S", XINPUT_GAMEPAD_DPAD_DOWN}, | 
					
						
							|  |  |  |                      {"Pad W", XINPUT_GAMEPAD_DPAD_LEFT}, | 
					
						
							|  |  |  |                      {"Pad E", XINPUT_GAMEPAD_DPAD_RIGHT}, | 
					
						
							|  |  |  |                      {"Start", XINPUT_GAMEPAD_START}, | 
					
						
							|  |  |  |                      {"Back", XINPUT_GAMEPAD_BACK}, | 
					
						
							|  |  |  |                      {"Shoulder L", XINPUT_GAMEPAD_LEFT_SHOULDER}, | 
					
						
							|  |  |  |                      {"Shoulder R", XINPUT_GAMEPAD_RIGHT_SHOULDER}, | 
					
						
							|  |  |  |                      {"Guide", XINPUT_GAMEPAD_GUIDE}, | 
					
						
							|  |  |  |                      {"Thumb L", XINPUT_GAMEPAD_LEFT_THUMB}, | 
					
						
							|  |  |  |                      {"Thumb R", XINPUT_GAMEPAD_RIGHT_THUMB}}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char* const named_triggers[] = {"Trigger L", "Trigger R"}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char* const named_axes[] = {"Left X", "Left Y", "Right X", "Right Y"}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char* const named_motors[] = {"Motor L", "Motor R"}; | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | static HMODULE hXInput = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef decltype(&XInputGetCapabilities) XInputGetCapabilities_t; | 
					
						
							|  |  |  | typedef decltype(&XInputSetState) XInputSetState_t; | 
					
						
							|  |  |  | typedef decltype(&XInputGetState) XInputGetState_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static XInputGetCapabilities_t PXInputGetCapabilities = nullptr; | 
					
						
							|  |  |  | static XInputSetState_t PXInputSetState = nullptr; | 
					
						
							|  |  |  | static XInputGetState_t PXInputGetState = nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-17 12:03:44 +01:00
										 |  |  | static bool haveGuideButton = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-12 17:08:04 +02:00
										 |  |  | void Init() | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (!hXInput) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // Try for the most recent version we were compiled against (will only work if running on Win8+)
 | 
					
						
							|  |  |  |     hXInput = ::LoadLibrary(XINPUT_DLL); | 
					
						
							|  |  |  |     if (!hXInput) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // Drop back to DXSDK June 2010 version. Requires DX June 2010 redist.
 | 
					
						
							|  |  |  |       hXInput = ::LoadLibrary(TEXT("xinput1_3.dll")); | 
					
						
							|  |  |  |       if (!hXInput) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PXInputGetCapabilities = | 
					
						
							|  |  |  |         (XInputGetCapabilities_t)::GetProcAddress(hXInput, "XInputGetCapabilities"); | 
					
						
							|  |  |  |     PXInputSetState = (XInputSetState_t)::GetProcAddress(hXInput, "XInputSetState"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Ordinal 100 is the same as XInputGetState, except it doesn't dummy out the guide
 | 
					
						
							|  |  |  |     // button info. Try loading it and fall back if needed.
 | 
					
						
							|  |  |  |     PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, (LPCSTR)100); | 
					
						
							|  |  |  |     if (PXInputGetState) | 
					
						
							|  |  |  |       haveGuideButton = true; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       PXInputGetState = (XInputGetState_t)::GetProcAddress(hXInput, "XInputGetState"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!PXInputGetCapabilities || !PXInputSetState || !PXInputGetState) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       ::FreeLibrary(hXInput); | 
					
						
							|  |  |  |       hXInput = nullptr; | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2016-10-16 13:39:05 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void PopulateDevices() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (!hXInput) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   XINPUT_CAPABILITIES caps; | 
					
						
							|  |  |  |   for (int i = 0; i != 4; ++i) | 
					
						
							|  |  |  |     if (ERROR_SUCCESS == PXInputGetCapabilities(i, 0, &caps)) | 
					
						
							| 
									
										
										
										
											2016-06-25 21:46:39 +02:00
										 |  |  |       g_controller_interface.AddDevice(std::make_shared<Device>(caps, i)); | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-19 02:27:57 -07:00
										 |  |  | void DeInit() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (hXInput) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     ::FreeLibrary(hXInput); | 
					
						
							|  |  |  |     hXInput = nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Device::Device(const XINPUT_CAPABILITIES& caps, u8 index) : m_subtype(caps.SubType), m_index(index) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-08-09 22:51:01 -05:00
										 |  |  |   // XInputGetCaps can be broken on some devices, so we'll just ignore it
 | 
					
						
							|  |  |  |   // and assume all gamepad + vibration capabilities are supported
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // get supported buttons
 | 
					
						
							|  |  |  |   for (int i = 0; i != sizeof(named_buttons) / sizeof(*named_buttons); ++i) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-08-09 22:51:01 -05:00
										 |  |  |     // Only add guide button if we have the 100 ordinal XInputGetState
 | 
					
						
							|  |  |  |     if (!(named_buttons[i].bitmask & XINPUT_GAMEPAD_GUIDE) || haveGuideButton) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       AddInput(new Button(i, m_state_in.Gamepad.wButtons)); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // get supported triggers
 | 
					
						
							|  |  |  |   for (int i = 0; i != sizeof(named_triggers) / sizeof(*named_triggers); ++i) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-08-09 22:51:01 -05:00
										 |  |  |     AddInput(new Trigger(i, (&m_state_in.Gamepad.bLeftTrigger)[i], 255)); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // get supported axes
 | 
					
						
							|  |  |  |   for (int i = 0; i != sizeof(named_axes) / sizeof(*named_axes); ++i) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-08-09 22:51:01 -05:00
										 |  |  |     const SHORT& ax = (&m_state_in.Gamepad.sThumbLX)[i]; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-09 22:51:01 -05:00
										 |  |  |     // each axis gets a negative and a positive input instance associated with it
 | 
					
						
							|  |  |  |     AddInput(new Axis(i, ax, -32768)); | 
					
						
							|  |  |  |     AddInput(new Axis(i, ax, 32767)); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // get supported motors
 | 
					
						
							|  |  |  |   for (int i = 0; i != sizeof(named_motors) / sizeof(*named_motors); ++i) | 
					
						
							|  |  |  |   { | 
					
						
							| 
									
										
										
										
											2017-08-09 22:51:01 -05:00
										 |  |  |     AddOutput(new Motor(i, this, (&m_state_out.wLeftMotorSpeed)[i], 65535)); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ZeroMemory(&m_state_in, sizeof(m_state_in)); | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string Device::GetName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   switch (m_subtype) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case XINPUT_DEVSUBTYPE_GAMEPAD: | 
					
						
							|  |  |  |     return "Gamepad"; | 
					
						
							|  |  |  |   case XINPUT_DEVSUBTYPE_WHEEL: | 
					
						
							|  |  |  |     return "Wheel"; | 
					
						
							|  |  |  |   case XINPUT_DEVSUBTYPE_ARCADE_STICK: | 
					
						
							|  |  |  |     return "Arcade Stick"; | 
					
						
							|  |  |  |   case XINPUT_DEVSUBTYPE_FLIGHT_STICK: | 
					
						
							|  |  |  |     return "Flight Stick"; | 
					
						
							|  |  |  |   case XINPUT_DEVSUBTYPE_DANCE_PAD: | 
					
						
							|  |  |  |     return "Dance Pad"; | 
					
						
							|  |  |  |   case XINPUT_DEVSUBTYPE_GUITAR: | 
					
						
							|  |  |  |     return "Guitar"; | 
					
						
							|  |  |  |   case XINPUT_DEVSUBTYPE_DRUM_KIT: | 
					
						
							|  |  |  |     return "Drum Kit"; | 
					
						
							|  |  |  |   default: | 
					
						
							|  |  |  |     return "Device"; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string Device::GetSource() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return "XInput"; | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-14 22:53:10 -04:00
										 |  |  | // Update I/O
 | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 00:55:14 -08:00
										 |  |  | void Device::UpdateInput() | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   PXInputGetState(m_index, &m_state_in); | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 01:10:55 -08:00
										 |  |  | void Device::UpdateMotors() | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   // this if statement is to make rumble work better when multiple ControllerInterfaces are using
 | 
					
						
							|  |  |  |   // the device
 | 
					
						
							|  |  |  |   // only calls XInputSetState if the state changed
 | 
					
						
							|  |  |  |   if (memcmp(&m_state_out, &m_current_state_out, sizeof(m_state_out))) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     m_current_state_out = m_state_out; | 
					
						
							|  |  |  |     PXInputSetState(m_index, &m_state_out); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GET name/source/id
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string Device::Button::GetName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return named_buttons[m_index].name; | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string Device::Axis::GetName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return std::string(named_axes[m_index]) + (m_range < 0 ? '-' : '+'); | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string Device::Trigger::GetName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return named_triggers[m_index]; | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | std::string Device::Motor::GetName() const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return named_motors[m_index]; | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GET / SET STATES
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 01:20:11 +00:00
										 |  |  | ControlState Device::Button::GetState() const | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return (m_buttons & named_buttons[m_index].bitmask) > 0; | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 01:20:11 +00:00
										 |  |  | ControlState Device::Trigger::GetState() const | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return ControlState(m_trigger) / m_range; | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 01:20:11 +00:00
										 |  |  | ControlState Device::Axis::GetState() const | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   return std::max(0.0, ControlState(m_axis) / m_range); | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-14 01:20:11 +00:00
										 |  |  | void Device::Motor::SetState(ControlState state) | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_motor = (WORD)(state * m_range); | 
					
						
							|  |  |  |   m_parent->UpdateMotors(); | 
					
						
							| 
									
										
										
										
											2010-04-02 02:48:24 +00:00
										 |  |  | } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | } |