1 /*
2  *  Copyright (C) 2014-2020 Garrett Brown
3  *  Copyright (C) 2014-2020 Team Kodi
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSE.md for more information.
7  */
8 
9 #include "JoystickXInput.h"
10 #include "JoystickInterfaceXInput.h"
11 #include "XInputDLL.h"
12 #include "api/JoystickTypes.h"
13 
14 #include <Xinput.h>
15 
16 using namespace JOYSTICK;
17 
18 #define XINPUT_ALIAS  "Xbox 360-compatible controller"
19 #define BUTTON_COUNT  15
20 #define HAT_COUNT     0 // hats are treated as buttons
21 #define AXIS_COUNT    6
22 #define MAX_AXIS      32768
23 #define MAX_TRIGGER   255
24 #define MAX_MOTOR     65535
25 
CJoystickXInput(unsigned int controllerID)26 CJoystickXInput::CJoystickXInput(unsigned int controllerID)
27  : CJoystick(EJoystickInterface::XINPUT),
28    m_controllerID(controllerID),
29    m_dwPacketNumber(0)
30 {
31   SetName(XINPUT_ALIAS);
32   SetRequestedPort(m_controllerID);
33   SetButtonCount(BUTTON_COUNT);
34   SetHatCount(HAT_COUNT);
35   SetAxisCount(AXIS_COUNT);
36   SetMotorCount(MOTOR_COUNT);
37 
38   m_motorSpeeds[MOTOR_LEFT] = 0.0f;
39   m_motorSpeeds[MOTOR_RIGHT] = 0.0f;
40 
41   SetSupportsPowerOff(true);
42 }
43 
Equals(const CJoystick * rhs) const44 bool CJoystickXInput::Equals(const CJoystick* rhs) const
45 {
46   if (rhs == nullptr)
47     return false;
48 
49   const CJoystickXInput* rhsXInput = dynamic_cast<const CJoystickXInput*>(rhs);
50   if (rhsXInput == nullptr)
51     return false;
52 
53   return m_controllerID == rhsXInput->m_controllerID;
54 }
55 
PowerOff()56 void CJoystickXInput::PowerOff()
57 {
58   if (CXInputDLL::Get().Version() == "1.3")
59     CXInputDLL::Get().PowerOff(m_controllerID);
60 }
61 
ScanEvents(void)62 bool CJoystickXInput::ScanEvents(void)
63 {
64   if (CXInputDLL::Get().Version() == "1.3")
65   {
66     XINPUT_STATE_EX controllerState;
67 
68     if (!CXInputDLL::Get().GetStateWithGuide(m_controllerID, controllerState))
69       return false;
70 
71     m_dwPacketNumber = controllerState.dwPacketNumber;
72 
73     SetButtonValue(0,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_A)              ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
74     SetButtonValue(1,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_B)              ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
75     SetButtonValue(2,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_X)              ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
76     SetButtonValue(3,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_Y)              ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
77     SetButtonValue(4,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER)  ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
78     SetButtonValue(5,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
79     SetButtonValue(6,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_BACK)           ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
80     SetButtonValue(7,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_START)          ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
81     SetButtonValue(8,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB)     ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
82     SetButtonValue(9,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB)    ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
83     SetButtonValue(10, (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)        ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
84     SetButtonValue(11, (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)     ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
85     SetButtonValue(12, (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)      ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
86     SetButtonValue(13, (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)      ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
87     SetButtonValue(14, (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE)          ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
88 
89     SetAxisValue(0, (long)controllerState.Gamepad.sThumbLX, MAX_AXIS);
90     SetAxisValue(1, (long)controllerState.Gamepad.sThumbLY, MAX_AXIS);
91     SetAxisValue(2, (long)controllerState.Gamepad.sThumbRX, MAX_AXIS);
92     SetAxisValue(3, (long)controllerState.Gamepad.sThumbRY, MAX_AXIS);
93     SetAxisValue(4, (long)controllerState.Gamepad.bLeftTrigger, MAX_TRIGGER);
94     SetAxisValue(5, (long)controllerState.Gamepad.bRightTrigger, MAX_TRIGGER);
95   }
96   else
97   {
98     XINPUT_STATE controllerState;
99 
100     if (!CXInputDLL::Get().GetState(m_controllerID, controllerState))
101       return false;
102 
103     m_dwPacketNumber = controllerState.dwPacketNumber;
104 
105     SetButtonValue(0,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_A)              ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
106     SetButtonValue(1,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_B)              ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
107     SetButtonValue(2,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_X)              ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
108     SetButtonValue(3,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_Y)              ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
109     SetButtonValue(4,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER)  ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
110     SetButtonValue(5,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
111     SetButtonValue(6,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_BACK)           ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
112     SetButtonValue(7,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_START)          ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
113     SetButtonValue(8,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB)     ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
114     SetButtonValue(9,  (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB)    ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
115     SetButtonValue(10, (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)        ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
116     SetButtonValue(11, (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)     ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
117     SetButtonValue(12, (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)      ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
118     SetButtonValue(13, (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)      ? JOYSTICK_STATE_BUTTON_PRESSED : JOYSTICK_STATE_BUTTON_UNPRESSED);
119 
120     SetAxisValue(0, (long)controllerState.Gamepad.sThumbLX, MAX_AXIS);
121     SetAxisValue(1, (long)controllerState.Gamepad.sThumbLY, MAX_AXIS);
122     SetAxisValue(2, (long)controllerState.Gamepad.sThumbRX, MAX_AXIS);
123     SetAxisValue(3, (long)controllerState.Gamepad.sThumbRY, MAX_AXIS);
124     SetAxisValue(4, (long)controllerState.Gamepad.bLeftTrigger, MAX_TRIGGER);
125     SetAxisValue(5, (long)controllerState.Gamepad.bRightTrigger, MAX_TRIGGER);
126   }
127 
128   return true;
129 }
130 
SetMotor(unsigned int motorIndex,float magnitude)131 bool CJoystickXInput::SetMotor(unsigned int motorIndex, float magnitude)
132 {
133   bool bSuccess = false;
134 
135   if (motorIndex < MOTOR_COUNT && 0.0f <= magnitude && magnitude <= 1.0f)
136   {
137     m_motorSpeeds[motorIndex] = magnitude;
138 
139     XINPUT_VIBRATION vibrationState;
140 
141     vibrationState.wLeftMotorSpeed = static_cast<WORD>(m_motorSpeeds[MOTOR_LEFT] * MAX_MOTOR);
142     vibrationState.wRightMotorSpeed = static_cast<WORD>(m_motorSpeeds[MOTOR_RIGHT] * MAX_MOTOR);
143 
144     // TODO: Only dispatch after both left and right events have been received
145     bSuccess = CXInputDLL::Get().SetState(m_controllerID, vibrationState);
146   }
147 
148   return bSuccess;
149 }
150