1 /***************************************************************************
2  *   Copyright (C) 2005-2019 by the FIFE team                              *
3  *   http://www.fifengine.net                                              *
4  *   This file is part of FIFE.                                            *
5  *                                                                         *
6  *   FIFE is free software; you can redistribute it and/or                 *
7  *   modify it under the terms of the GNU Lesser General Public            *
8  *   License as published by the Free Software Foundation; either          *
9  *   version 2.1 of the License, or (at your option) any later version.    *
10  *                                                                         *
11  *   This library is distributed in the hope that it will be useful,       *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
14  *   Lesser General Public License for more details.                       *
15  *                                                                         *
16  *   You should have received a copy of the GNU Lesser General Public      *
17  *   License along with this library; if not, write to the                 *
18  *   Free Software Foundation, Inc.,                                       *
19  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <iostream>
24 
25 // 3rd party library includes
26 #include <SDL.h>
27 
28 // FIFE includes
29 // These includes are split up in two parts, separated by one empty line
30 // First block: files included from the FIFE root src directory
31 // Second block: files included from the same folder
32 #include "util/base/exception.h"
33 #include "util/log/logger.h"
34 #include "util/math/fife_math.h"
35 
36 #include "joystick.h"
37 
38 namespace FIFE {
39 	static Logger _log(LM_EVTCHANNEL);
40 
Joystick(int32_t joystickId,int32_t deviceIndex)41 	Joystick::Joystick(int32_t joystickId, int32_t deviceIndex):
42 		m_joystickHandle(NULL),
43 		m_controllerHandle(NULL),
44 		m_instanceId(-1),
45 		m_joystickId(joystickId),
46 		m_deviceIndex(deviceIndex),
47 		m_guidStr(""),
48 		m_name("") {
49 
50 	}
51 
~Joystick()52 	Joystick::~Joystick() {
53 		close();
54 	}
55 
getInstanceId() const56 	int32_t Joystick::getInstanceId() const {
57 		return static_cast<int32_t>(m_instanceId);
58 	}
59 
getJoystickId() const60 	int32_t Joystick::getJoystickId() const {
61 		return m_joystickId;
62 	}
63 
setDeviceIndex(int32_t deviceIndex)64 	void Joystick::setDeviceIndex(int32_t deviceIndex) {
65 		m_deviceIndex = deviceIndex;
66 	}
67 
getDeviceIndex() const68 	int32_t Joystick::getDeviceIndex() const {
69 		return m_deviceIndex;
70 	}
71 
getGuid()72 	const std::string& Joystick::getGuid() {
73 		return m_guidStr;
74 	}
75 
getName()76 	const std::string& Joystick::getName() {
77 		return m_name;
78 	}
79 
open()80 	void Joystick::open() {
81 		if (m_joystickHandle) {
82 			close();
83 		}
84 
85 		m_joystickHandle = SDL_JoystickOpen(m_deviceIndex);
86 		if (m_joystickHandle) {
87 			m_instanceId = SDL_JoystickInstanceID(m_joystickHandle);
88 
89 			char tmp[33];
90 			SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(m_deviceIndex);
91 			SDL_JoystickGetGUIDString(guid, tmp, sizeof(tmp));
92 			m_guidStr = std::string(tmp);
93 
94 			openController();
95 			const char* name = SDL_JoystickNameForIndex(m_deviceIndex);
96 			if (isController() && !name) {
97 				name = SDL_GameControllerNameForIndex(m_deviceIndex);
98 			}
99 			m_name = std::string(name);
100 		} else {
101 			throw SDLException(SDL_GetError());
102 		}
103 	}
104 
close()105 	void Joystick::close() {
106 		closeController();
107 		if (m_joystickHandle) {
108 			SDL_JoystickClose(m_joystickHandle);
109 			m_joystickHandle = NULL;
110 		}
111 		m_instanceId = -1;
112 		m_deviceIndex = -1;
113 	}
114 
isConnected() const115 	bool Joystick::isConnected() const {
116 		return m_joystickHandle && SDL_JoystickGetAttached(m_joystickHandle);
117 	}
118 
isController() const119 	bool Joystick::isController() const {
120 		return m_controllerHandle != NULL;
121 	}
122 
openController()123 	void Joystick::openController() {
124 		closeController();
125 		if (!SDL_IsGameController(m_deviceIndex)) {
126 			return;
127 		}
128 
129 		m_controllerHandle = SDL_GameControllerOpen(m_deviceIndex);
130 	}
131 
closeController()132 	void Joystick::closeController() {
133 		if (m_controllerHandle) {
134 			SDL_GameControllerClose(m_controllerHandle);
135 			m_controllerHandle = NULL;
136 		}
137 	}
138 
getNumberOfAxes() const139 	uint8_t Joystick::getNumberOfAxes() const {
140 		uint8_t number = 0;
141 		if (isConnected()) {
142 			number = SDL_JoystickNumAxes(m_joystickHandle);
143 		}
144 		return number;
145 	}
146 
getNumberOfButtons() const147 	uint8_t Joystick::getNumberOfButtons() const {
148 		uint8_t number = 0;
149 		if (isConnected()) {
150 			number = SDL_JoystickNumButtons(m_joystickHandle);
151 		}
152 		return number;
153 	}
154 
getNumberOfHats() const155 	uint8_t Joystick::getNumberOfHats() const {
156 		uint8_t number = 0;
157 		if (isConnected()) {
158 			number = SDL_JoystickNumHats(m_joystickHandle);
159 		}
160 		return number;
161 	}
162 
getAxisValue(int8_t axis) const163 	float Joystick::getAxisValue(int8_t axis) const {
164 		if (axis < 0 || !isConnected()) {
165 			return 0;
166 		}
167 
168 		if (!isController()) {
169 			return convertRange(SDL_JoystickGetAxis(m_joystickHandle, axis));
170 		}
171 
172 		SDL_GameControllerAxis sdlAxis = static_cast<SDL_GameControllerAxis>(axis);
173 		return convertRange(SDL_GameControllerGetAxis(m_controllerHandle, sdlAxis));
174 	}
175 
getHatValue(int8_t hat) const176 	int8_t Joystick::getHatValue(int8_t hat) const {
177 		if (hat < 0 || !isConnected()) {
178 			return HAT_INVALID;
179 		}
180 		return SDL_JoystickGetHat(m_joystickHandle, hat);
181 	}
182 
isButtonPressed(int8_t button) const183 	bool Joystick::isButtonPressed(int8_t button) const {
184 		if (button < 0 || !isConnected()) {
185 			return false;
186 		}
187 		if (!isController()) {
188 			if (SDL_JoystickGetButton(m_joystickHandle, button) == 1) {
189 				return true;
190 			}
191 			return false;
192 		}
193 
194 		SDL_GameControllerButton sdlButton = static_cast<SDL_GameControllerButton>(button);
195 		if (SDL_GameControllerGetButton(m_controllerHandle, sdlButton) == 1) {
196 			return true;
197 		}
198 		return false;
199 	}
200 
convertRange(int16_t value) const201 	float Joystick::convertRange(int16_t value) const {
202 		float range = static_cast<float>(value) / 32768.0f;
203 		if (Mathf::FAbs(range) < 0.01f) {
204 			return 0.0f;
205 		}
206 		if (range < -0.99f) {
207 			return -1.0f;
208 		} else if (range > 0.99f) {
209 			return 1.0f;
210 		}
211 		return range;
212 	}
213 }
214