1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt Gamepad module
7 **
8 ** $QT_BEGIN_LICENSE:LGPL3$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or later as published by the Free
28 ** Software Foundation and appearing in the file LICENSE.GPL included in
29 ** the packaging of this file. Please review the following information to
30 ** ensure the GNU General Public License version 2.0 requirements will be
31 ** met: http://www.gnu.org/licenses/gpl-2.0.html.
32 **
33 ** $QT_END_LICENSE$
34 **
35 ****************************************************************************/
36 #include "qsdlgamepadbackend_p.h"
37
38 #include <QtCore/QDebug>
39
40 #include <SDL.h>
41 // Reset bool redefinition from SDL header
42 #undef bool
43
44 QT_BEGIN_NAMESPACE
45
QSdlGamepadBackend(QObject * parent)46 QSdlGamepadBackend::QSdlGamepadBackend(QObject *parent)
47 : QGamepadBackend(parent)
48 {
49 connect(&m_eventLoopTimer, SIGNAL(timeout()), this, SLOT(pumpSdlEventLoop()));
50 }
51
~QSdlGamepadBackend()52 QSdlGamepadBackend::~QSdlGamepadBackend()
53 {
54 }
55
pumpSdlEventLoop()56 void QSdlGamepadBackend::pumpSdlEventLoop()
57 {
58 SDL_Event event;
59 while (SDL_PollEvent(&event)) {
60 if (event.type == SDL_CONTROLLERAXISMOTION) {
61 SDL_ControllerAxisEvent axisEvent = event.caxis;
62 //qDebug() << axisEvent.timestamp << "Axis Event: " << axisEvent.which << axisEvent.axis << axisEvent.value;
63 double value;
64 if (axisEvent.value >= 0)
65 value = axisEvent.value / 32767.0;
66 else
67 value = axisEvent.value / 32768.0;
68 switch (axisEvent.axis) {
69 case SDL_CONTROLLER_AXIS_LEFTX:
70 emit gamepadAxisMoved(m_instanceIdForIndex[axisEvent.which], QGamepadManager::AxisLeftX, value);
71 break;
72 case SDL_CONTROLLER_AXIS_LEFTY:
73 emit gamepadAxisMoved(m_instanceIdForIndex[axisEvent.which], QGamepadManager::AxisLeftY, value);
74 break;
75 case SDL_CONTROLLER_AXIS_RIGHTX:
76 emit gamepadAxisMoved(m_instanceIdForIndex[axisEvent.which], QGamepadManager::AxisRightX, value);
77 break;
78 case SDL_CONTROLLER_AXIS_RIGHTY:
79 emit gamepadAxisMoved(m_instanceIdForIndex[axisEvent.which], QGamepadManager::AxisRightY, value);
80 break;
81 case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
82 if (value == 0)
83 emit gamepadButtonReleased(m_instanceIdForIndex[axisEvent.which], QGamepadManager::ButtonL2);
84 else
85 emit gamepadButtonPressed(m_instanceIdForIndex[axisEvent.which], QGamepadManager::ButtonL2, value);
86 break;
87 case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
88 if (value == 0)
89 emit gamepadButtonReleased(m_instanceIdForIndex[axisEvent.which], QGamepadManager::ButtonR2);
90 else
91 emit gamepadButtonPressed(m_instanceIdForIndex[axisEvent.which], QGamepadManager::ButtonR2, value);
92 break;
93 default:
94 break;
95 }
96
97 } else if (event.type == SDL_CONTROLLERBUTTONDOWN) {
98 SDL_ControllerButtonEvent buttonEvent = event.cbutton;
99 //qDebug() << buttonEvent.timestamp << "Button Press: " << buttonEvent.which << buttonEvent.button << buttonEvent.state;
100 emit gamepadButtonPressed(m_instanceIdForIndex[buttonEvent.which], translateButton(buttonEvent.button), 1.0);
101 } else if (event.type == SDL_CONTROLLERBUTTONUP) {
102 SDL_ControllerButtonEvent buttonEvent = event.cbutton;
103 //qDebug() << buttonEvent.timestamp << "Button Release: " << buttonEvent.which << buttonEvent.button << buttonEvent.state;
104 emit gamepadButtonReleased(m_instanceIdForIndex[buttonEvent.which], translateButton(buttonEvent.button));
105 } else if (event.type == SDL_CONTROLLERDEVICEADDED) {
106 SDL_ControllerDeviceEvent deviceEvent = event.cdevice;
107 //qDebug() << deviceEvent.timestamp << "Controller Added: " << deviceEvent.which;
108 addController(deviceEvent.which);
109 } else if (event.type == SDL_CONTROLLERDEVICEREMOVED) {
110 SDL_ControllerDeviceEvent deviceEvent = event.cdevice;
111
112 int index = m_instanceIdForIndex[deviceEvent.which];
113 SDL_GameControllerClose(m_indexForController[index]);
114 emit gamepadRemoved(index);
115 m_indexForController.remove(index);
116 m_instanceIdForIndex.remove(deviceEvent.which);
117
118 } else if (event.type == SDL_CONTROLLERDEVICEREMAPPED) {
119 //SDL_ControllerDeviceEvent deviceEvent = event.cdevice;
120 //qDebug() << deviceEvent.timestamp << "Controller Remapped: " << deviceEvent.which;
121 }
122 }
123 }
124
start()125 bool QSdlGamepadBackend::start()
126 {
127 //Initialize SDL with necessary subsystems for gamepad support
128 if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK)) {
129 qDebug() << SDL_GetError();
130 return false;
131 }
132
133 m_eventLoopTimer.start(16);
134 for (int i = 0; i < SDL_NumJoysticks() ; i++)
135 addController(i);
136
137 return true;
138 }
139
stop()140 void QSdlGamepadBackend::stop()
141 {
142 m_eventLoopTimer.stop();
143 SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK);
144 }
145
translateButton(int button)146 QGamepadManager::GamepadButton QSdlGamepadBackend::translateButton(int button)
147 {
148 switch (button) {
149 case SDL_CONTROLLER_BUTTON_A:
150 return QGamepadManager::ButtonA;
151 case SDL_CONTROLLER_BUTTON_B:
152 return QGamepadManager::ButtonB;
153 case SDL_CONTROLLER_BUTTON_X:
154 return QGamepadManager::ButtonX;
155 case SDL_CONTROLLER_BUTTON_Y:
156 return QGamepadManager::ButtonY;
157 case SDL_CONTROLLER_BUTTON_BACK:
158 return QGamepadManager::ButtonSelect;
159 case SDL_CONTROLLER_BUTTON_GUIDE:
160 return QGamepadManager::ButtonGuide;
161 case SDL_CONTROLLER_BUTTON_START:
162 return QGamepadManager::ButtonStart;
163 case SDL_CONTROLLER_BUTTON_LEFTSTICK:
164 return QGamepadManager::ButtonL3;
165 case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
166 return QGamepadManager::ButtonR3;
167 case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
168 return QGamepadManager::ButtonL1;
169 case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
170 return QGamepadManager::ButtonR1;
171 case SDL_CONTROLLER_BUTTON_DPAD_UP:
172 return QGamepadManager::ButtonUp;
173 case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
174 return QGamepadManager::ButtonDown;
175 case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
176 return QGamepadManager::ButtonLeft;
177 case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
178 return QGamepadManager::ButtonRight;
179 default:
180 return QGamepadManager::ButtonInvalid;
181 }
182 }
183
addController(int index)184 void QSdlGamepadBackend::addController(int index)
185 {
186 char GUID[100];
187 SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(index), GUID, 100);
188 if (!SDL_IsGameController(index))
189 return;
190
191 SDL_GameController *controller = SDL_GameControllerOpen(index);
192 if (controller) {
193 m_indexForController.insert(index, controller);
194
195 SDL_Joystick *joystick = SDL_GameControllerGetJoystick(controller);
196
197 int instanceID = SDL_JoystickInstanceID(joystick);
198 m_instanceIdForIndex.insert(instanceID, index);
199
200 const char *name = SDL_JoystickName(joystick);
201
202 //qDebug() << "Controller " << index << " added with instanceId: " << instanceID;
203 emit gamepadAdded(index);
204
205 if (name)
206 emit gamepadNamed(index, QString::fromUtf8(name));
207 }
208 }
209
210 QT_END_NAMESPACE
211