Bubba-3D  0.9.0
Awesome game engine!
JoystickTranslator.cpp
1 /*
2  * This file is part of Bubba-3D.
3  *
4  * Bubba-3D is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * Bubba-3D is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with Bubba-3D. If not, see http://www.gnu.org/licenses/.
16  */
17 //
18 // Created by simon on 2016-01-14.
19 //
20 
21 #include <JoystickTranslator.h>
22 #include <stdexcept>
23 #include <rapidjson/filereadstream.h>
24 #include <rapidjson/document.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <SFML/Window.hpp>
28 #include <IJoystickTranslation.h>
29 #include <JoystickTranslation.h>
30 #include <Logger.h>
31 
32 using namespace rapidjson;
33 using namespace std;
34 
35 JoystickTranslator::JoystickTranslator() {
36 
37 }
38 
39 JoystickTranslator *JoystickTranslator::getInstance() {
40  static JoystickTranslator jt;
41  return &jt;
42 }
43 
44 void JoystickTranslator::init(string filePath) {
45 
46  struct stat filestatus;
47  stat(filePath.c_str(), &filestatus);
48  const unsigned long long size = filestatus.st_size;
49 
50  std::FILE *file = fopen(filePath.c_str(), "r");
51  char readBuffer[100000];
52  FileReadStream rs(file, readBuffer, size);
53 
54  jsonConfig = new Document();
55  jsonConfig->ParseStream<kParseCommentsFlag>(rs);
56  try {
57  readDocument(jsonConfig);
58  } catch (std::string error) {
59  Logger::logError("Failed reading controls: " + error);
60  }
61 }
62 
63 void JoystickTranslator::updateMapping() {
64  try {
65  readDocument(jsonConfig);
66  } catch (std::string error) {
67  Logger::logError("Failed reading controls: " + error);
68  }
69 }
70 
71 JoystickTranslator::~JoystickTranslator() {
72 
73 }
74 
75 void JoystickTranslator::readDocument(Document *doc) {
76  check(doc->IsArray(), "Document was not array.");
77  bool joysticksFound[8] = {false, false, false, false, false, false, false, false};
78  Value *def;
79  bool defFound = false;
80  for (SizeType i = 0; i < doc->Size(); i++) {
81  int devId = (*doc)[i]["deviceID"].GetInt();
82  int vendId = (*doc)[i]["vendorID"].GetInt();
83  int js = -1;
84  while ((js = getJoystick(devId, vendId, js + 1)) != -1) {
85  readMappings(&((*doc)[i]["mappings"]), js, false);
86  joysticksFound[js] = true;
87  }
88  if ((*doc)[i].HasMember("default") && (*doc)[i]["default"].GetBool()) {
89  defFound = true;
90  def = &(*doc)[i]["mappings"];
91  }
92  }
93  if (!defFound)
94  throw "There was no default mapping.";
95  for (unsigned int found = 0; found < 8; found++) {
96  if (sf::Joystick::isConnected(found) && !joysticksFound[found])
97  readMappings(def, found, true);
98  }
99 }
100 
101 void JoystickTranslator::readMappings(Value *mappings, unsigned int joystick, bool defaultMapping) {
102  check(mappings->IsArray(), "The mappings wasn't an array.");
103  translations.push_back(JoystickTranslation(joystick, defaultMapping));
104  for (SizeType i = 0; i < mappings->Size(); i++) {
105  string type = (*mappings)[i]["type"].GetString();
106  string button = (*mappings)[i]["xbox"].GetString();
107  if (type == "button") {
108  translations.back().addButton(buttonFromString(button),
109  decideOnButtonRetriever(&(*mappings)[i]["generic"]));
110  } else if (type == "axis") {
111  translations.back().addAxis(axisFromString(button),
112  decideOnAxisRetriever(&(*mappings)[i]["generic"], button));
113  } else {
114  throw "Invalid type in button " + button;
115  }
116  }
117 }
118 
119 JoystickTranslation::valueRetriever JoystickTranslator::decideOnButtonRetriever(Value *mapData) {
120  check(mapData->IsObject(), "value wasn't object when checking button generic.");
121  string type = (*mapData)["type"].GetString();
122  if (type == "button")
123  return JoystickTranslation::buttonValueRetriever((*mapData)["buttonID"].GetUint());
124  else if (type == "axis") {
125  return JoystickTranslation::buttonFromAxisRetriever(
126  SFMLAxisFromString((*mapData)["name"].GetString()));
127  } else if (type == "halfAxis") {
128  return JoystickTranslation::buttonFromHalfAxisRetriever(
129  SFMLAxisFromString((*mapData)["name"].GetString()),
130  (*mapData)["positiveElseNegative"].GetBool());
131  } else if (type == "none") {
132  return JoystickTranslation::valRetriever(0.0f);
133  } else
134  throw "Unknown type: " + type + " when deciding button retriever.";
135 }
136 
137 JoystickTranslation::valueRetriever JoystickTranslator::decideOnAxisRetriever(Value *mapData, string axisName) {
138  check(mapData->IsObject(), "value wasn't object when checking button generic.");
139  string type = (*mapData)["type"].GetString();
140  if (type == "button")
141  return JoystickTranslation::axisFromButtonRetriever((*mapData)["buttonID"].GetUint());
142  else if (type == "axis")
143  return JoystickTranslation::axisValueRetriever(
144  SFMLAxisFromString(string((*mapData)["name"].GetString())), (*mapData)["inverted"].GetBool());
145  else if (type == "buttons")
146  return JoystickTranslation::axisFromButtonsRetriever((*mapData)["buttonNeg"].GetUint(),
147  (*mapData)["buttonPos"].GetUint());
148  else if (type == "none")
149  return JoystickTranslation::valRetriever(axisName == "RT" || axisName == "LT" ? -100.0f : 0.0f);
150  else
151  throw "Unknown type: " + type + " when deciding axis retriever.";
152 }
153 
154 int JoystickTranslator::getJoystick(unsigned int devId, unsigned int vendId, unsigned int startAt = 0) {
155  for (unsigned int i = startAt; i < sf::Joystick::Count; i++) {
156  sf::Joystick::Identification id = sf::Joystick::getIdentification(i);
157  if (id.productId == devId && id.vendorId == vendId)
158  return i;
159  }
160  return -1;
161 }
162 
163 void JoystickTranslator::check(bool ch, string message) {
164  if (!ch)
165  throw message;
166 }
167 
168 IJoystickTranslation *JoystickTranslator::getTranslation(unsigned int joystickID) {
169  if (joystickID >= sf::Joystick::Count)
170  throw std::invalid_argument("The parameter joystick was " + std::to_string(joystickID) +
171  " but must be less than " + std::to_string(sf::Joystick::Count));
172  for (auto it = translations.begin(); it != translations.end(); ++it) {
173  if ((*it).getJoystickID() == joystickID)
174  return &*it;
175  }
176  throw std::invalid_argument("The joystick " + std::to_string(joystickID) + " isn't connected.");
177 }
178 
179 IJoystickTranslation::Button JoystickTranslator::buttonFromString(std::string name) {
180  if (name == "X")
181  return IJoystickTranslation::Button::X;
182  if (name == "A")
183  return IJoystickTranslation::Button::A;
184  if (name == "B")
185  return IJoystickTranslation::Button::B;
186  if (name == "Y")
187  return IJoystickTranslation::Button::Y;
188  if (name == "START")
189  return IJoystickTranslation::Button::START;
190  if (name == "BACK")
191  return IJoystickTranslation::Button::BACK;
192  if (name == "GUIDE")
193  return IJoystickTranslation::Button::GUIDE;
194  if (name == "LB")
195  return IJoystickTranslation::Button::LB;
196  if (name == "RB")
197  return IJoystickTranslation::Button::RB;
198  if (name == "LEFT_THUMBSTICK_PUSH")
199  return IJoystickTranslation::Button::LEFT_THUMBSTICK_PUSH;
200  if (name == "RIGHT_THUMBSTICK_PUSH")
201  return IJoystickTranslation::Button::RIGHT_THUMBSTICK_PUSH;
202  throw std::invalid_argument(name + " is not a button.");
203 }
204 
205 IJoystickTranslation::Axis JoystickTranslator::axisFromString(std::string name) {
206  if (name == "DPAD_X")
207  return IJoystickTranslation::Axis::DPAD_X;
208  if (name == "DPAD_Y")
209  return IJoystickTranslation::Axis::DPAD_Y;
210  if (name == "LEFT_THUMBSTICK_X")
211  return IJoystickTranslation::Axis::LEFT_THUMBSTICK_X;
212  if (name == "LEFT_THUMBSTICK_Y")
213  return IJoystickTranslation::Axis::LEFT_THUMBSTICK_Y;
214  if (name == "RIGHT_THUMBSTICK_X")
215  return IJoystickTranslation::Axis::RIGHT_THUMBSTICK_X;
216  if (name == "RIGHT_THUMBSTICK_Y")
217  return IJoystickTranslation::Axis::RIGHT_THUMBSTICK_Y;
218  if (name == "LT")
219  return IJoystickTranslation::Axis::LT;
220  if (name == "RT")
221  return IJoystickTranslation::Axis::RT;
222  throw std::invalid_argument(name + " is not an axis.");
223 }
224 
225 sf::Joystick::Axis JoystickTranslator::SFMLAxisFromString(std::string name) {
226  if (name == "X")
227  return sf::Joystick::Axis::X;
228  if (name == "PovX")
229  return sf::Joystick::Axis::PovX;
230  if (name == "PovY")
231  return sf::Joystick::Axis::PovY;
232  if (name == "Y")
233  return sf::Joystick::Axis::Y;
234  if (name == "Z")
235  return sf::Joystick::Axis::Z;
236  if (name == "R")
237  return sf::Joystick::Axis::R;
238  if (name == "U")
239  return sf::Joystick::Axis::U;
240  if (name == "V")
241  return sf::Joystick::Axis::V;
242  throw std::invalid_argument(name + " is not an SFML axis.");
243 }