💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

532 lines
12 KiB

7 years ago
  1. /*
  2. * Copyright (C) 2017 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper Source Code.
  5. *
  6. * Antkeeper Source Code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper Source Code 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
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "controls.hpp"
  20. #include <sstream>
  21. #include <fstream>
  22. #include <vector>
  23. Control::Control():
  24. deadzone(0.1f),
  25. currentValue(0.0f),
  26. previousValue(0.0f)
  27. {}
  28. Control::~Control()
  29. {}
  30. void Control::setDeadzone(float value)
  31. {
  32. deadzone = value;
  33. }
  34. void Control::update()
  35. {
  36. previousValue = currentValue;
  37. }
  38. bool Control::isTriggered() const
  39. {
  40. return currentValue > deadzone;
  41. }
  42. bool Control::wasTriggered() const
  43. {
  44. return previousValue > deadzone;
  45. }
  46. bool Control::isUnbound() const
  47. {
  48. return (boundKeys.empty() && boundMouseButtons.empty() && boundGamepadButtons.empty() && boundGamepadAxes.empty());
  49. }
  50. void Control::bindKey(Keyboard* keyboard, int scancode)
  51. {
  52. // Check if already observing this keyboard
  53. bool observing = false;
  54. for (auto it: boundKeys)
  55. {
  56. if (it.first == keyboard)
  57. {
  58. observing = true;
  59. break;
  60. }
  61. }
  62. if (!observing)
  63. keyboard->addKeyObserver(static_cast<KeyObserver*>(this));
  64. boundKeys.push_back(std::pair<Keyboard*, int>(keyboard, scancode));
  65. }
  66. void Control::bindMouseButton(Mouse* mouse, int button)
  67. {
  68. // Checking if already observing this mouse
  69. bool observing = false;
  70. for (auto it: boundMouseButtons)
  71. {
  72. if (it.first == mouse)
  73. {
  74. observing = true;
  75. break;
  76. }
  77. }
  78. if (!observing)
  79. mouse->addMouseButtonObserver(static_cast<MouseButtonObserver*>(this));
  80. boundMouseButtons.push_back(std::pair<Mouse*, int>(mouse, button));
  81. }
  82. void Control::bindGamepadButton(Gamepad* gamepad, int button)
  83. {
  84. bool observing = false;
  85. for (auto it: boundGamepadButtons)
  86. {
  87. if (it.first == gamepad)
  88. {
  89. observing = true;
  90. break;
  91. }
  92. }
  93. if (!observing)
  94. gamepad->addGamepadButtonObserver(static_cast<GamepadButtonObserver*>(this));
  95. boundGamepadButtons.push_back(std::pair<Gamepad*, int>(gamepad, button));
  96. }
  97. void Control::bindGamepadAxis(Gamepad* gamepad, int axis, bool negative)
  98. {
  99. bool observing = false;
  100. for (auto it: boundGamepadAxes)
  101. {
  102. if (std::get<0>(it) == gamepad)
  103. {
  104. observing = true;
  105. break;
  106. }
  107. }
  108. if (!observing)
  109. gamepad->addGamepadAxisObserver(static_cast<GamepadAxisObserver*>(this));
  110. boundGamepadAxes.push_back(std::make_tuple(gamepad, axis, negative));
  111. }
  112. void Control::bind(const InputEvent& event)
  113. {
  114. switch (event.type)
  115. {
  116. case InputEvent::Type::KEY:
  117. bindKey(event.key.first, event.key.second);
  118. break;
  119. case InputEvent::Type::MOUSE_BUTTON:
  120. bindMouseButton(event.mouseButton.first, event.mouseButton.second);
  121. break;
  122. case InputEvent::Type::GAMEPAD_BUTTON:
  123. bindGamepadButton(event.gamepadButton.first, event.gamepadButton.second);
  124. break;
  125. case InputEvent::Type::GAMEPAD_AXIS:
  126. bindGamepadAxis(std::get<0>(event.gamepadAxis), std::get<1>(event.gamepadAxis), std::get<2>(event.gamepadAxis));
  127. break;
  128. default:
  129. break;
  130. }
  131. }
  132. void Control::unbind()
  133. {
  134. while (!boundKeys.empty())
  135. {
  136. // Remove the first bound key and stop observing its keyboard
  137. Keyboard* keyboard = boundKeys.front().first;
  138. keyboard->removeKeyObserver(static_cast<KeyObserver*>(this));
  139. boundKeys.pop_front();
  140. // Remove other bound keys which are associated with the keyboard
  141. auto it = boundKeys.begin();
  142. while (it != boundKeys.end())
  143. {
  144. if (it->first == keyboard)
  145. boundKeys.erase(it++);
  146. else
  147. ++it;
  148. }
  149. }
  150. while (!boundMouseButtons.empty())
  151. {
  152. // Remove the first bound mouse button and stop observing its mouse
  153. Mouse* mouse = boundMouseButtons.front().first;
  154. mouse->removeMouseButtonObserver(static_cast<MouseButtonObserver*>(this));
  155. boundMouseButtons.pop_front();
  156. // Remove other bound mouse buttons which are associated with the mouse
  157. auto it = boundMouseButtons.begin();
  158. while (it != boundMouseButtons.end())
  159. {
  160. if (it->first == mouse)
  161. boundMouseButtons.erase(it++);
  162. else
  163. ++it;
  164. }
  165. }
  166. while (!boundGamepadButtons.empty())
  167. {
  168. // Remove the first bound gamepad button and stop observing its gamepad
  169. Gamepad* gamepad = boundGamepadButtons.front().first;
  170. gamepad->removeGamepadButtonObserver(static_cast<GamepadButtonObserver*>(this));
  171. boundGamepadButtons.pop_front();
  172. // Remove other bound gamepad buttons which are associated with the gamepad
  173. auto it = boundGamepadButtons.begin();
  174. while (it != boundGamepadButtons.end())
  175. {
  176. if (it->first == gamepad)
  177. boundGamepadButtons.erase(it++);
  178. else
  179. ++it;
  180. }
  181. }
  182. while (!boundGamepadAxes.empty())
  183. {
  184. // Remove the first bound gamepad axis and stop observing its gamepad
  185. Gamepad* gamepad = std::get<0>(boundGamepadAxes.front());
  186. gamepad->removeGamepadAxisObserver(static_cast<GamepadAxisObserver*>(this));
  187. boundGamepadAxes.pop_front();
  188. // Remove other bound gamepad axes which are associated with the gamepad
  189. auto it = boundGamepadAxes.begin();
  190. while (it != boundGamepadAxes.end())
  191. {
  192. if (std::get<0>(*it) == gamepad)
  193. boundGamepadAxes.erase(it++);
  194. else
  195. ++it;
  196. }
  197. }
  198. }
  199. void Control::keyPressed(int scancode)
  200. {
  201. for (auto it: boundKeys)
  202. {
  203. if (it.second == scancode)
  204. {
  205. currentValue = 1.0f;
  206. break;
  207. }
  208. }
  209. }
  210. void Control::keyReleased(int scancode)
  211. {
  212. for (auto it: boundKeys)
  213. {
  214. if (it.second == scancode)
  215. {
  216. currentValue = 0.0f;
  217. break;
  218. }
  219. }
  220. }
  221. void Control::mouseButtonPressed(int button, int x, int y)
  222. {
  223. for (auto it: boundMouseButtons)
  224. {
  225. if (it.second == button)
  226. {
  227. currentValue = 1.0f;
  228. break;
  229. }
  230. }
  231. }
  232. void Control::mouseButtonReleased(int button, int x, int y)
  233. {
  234. for (auto it: boundMouseButtons)
  235. {
  236. if (it.second == button)
  237. {
  238. currentValue = 0.0f;
  239. break;
  240. }
  241. }
  242. }
  243. void Control::gamepadButtonPressed(int button)
  244. {
  245. for (auto it: boundGamepadButtons)
  246. {
  247. if (it.second == button)
  248. {
  249. currentValue = 1.0f;
  250. break;
  251. }
  252. }
  253. }
  254. void Control::gamepadButtonReleased(int button)
  255. {
  256. for (auto it: boundGamepadButtons)
  257. {
  258. if (it.second == button)
  259. {
  260. currentValue = 0.0f;
  261. break;
  262. }
  263. }
  264. }
  265. void Control::gamepadAxisMoved(int axis, bool negative, float value)
  266. {
  267. for (auto it: boundGamepadAxes)
  268. {
  269. if (std::get<1>(it) == axis && std::get<2>(it) == negative)
  270. {
  271. currentValue = value;
  272. break;
  273. }
  274. }
  275. }
  276. const std::list<std::pair<Keyboard*, int>>* Control::getBoundKeys() const
  277. {
  278. return &boundKeys;
  279. }
  280. const std::list<std::pair<Mouse*, int>>* Control::getBoundMouseButtons() const
  281. {
  282. return &boundMouseButtons;
  283. }
  284. const std::list<std::pair<Gamepad*, int>>* Control::getBoundGamepadButtons() const
  285. {
  286. return &boundGamepadButtons;
  287. }
  288. const std::list<std::tuple<Gamepad*, int, bool>>* Control::getBoundGamepadAxes() const
  289. {
  290. return &boundGamepadAxes;
  291. }
  292. ControlProfile::ControlProfile(InputManager* inputManager):
  293. inputManager(inputManager)
  294. {}
  295. void ControlProfile::registerControl(const std::string& name, Control* control)
  296. {
  297. controls[name] = control;
  298. }
  299. bool ControlProfile::save(const std::string& filename)
  300. {
  301. // Open control profile
  302. std::ofstream file(filename.c_str());
  303. if (!file.is_open())
  304. {
  305. std::cerr << "Failed to open control profile \"" << filename << "\"" << std::endl;
  306. return false;
  307. }
  308. for (auto it = controls.begin(); it != controls.end(); ++it)
  309. {
  310. Control* control = it->second;
  311. const std::list<std::pair<Keyboard*, int>>* boundKeys = control->getBoundKeys();
  312. const std::list<std::pair<Mouse*, int>>* boundMouseButtons = control->getBoundMouseButtons();
  313. const std::list<std::pair<Gamepad*, int>>* boundGamepadButtons = control->getBoundGamepadButtons();
  314. const std::list<std::tuple<Gamepad*, int, bool>>* boundGamepadAxes = control->getBoundGamepadAxes();
  315. for (auto boundKey: *boundKeys)
  316. {
  317. int key = boundKey.second;
  318. file << "control\t" << it->first << "\tkeyboard\tkey\t" << key << '\n';
  319. }
  320. for (auto boundMouseButton: *boundMouseButtons)
  321. {
  322. int button = boundMouseButton.second;
  323. file << "control\t" << it->first << "\tmouse\tbutton\t" << button << '\n';
  324. }
  325. for (auto boundGamepadButton: *boundGamepadButtons)
  326. {
  327. const std::string& gamepadName = boundGamepadButton.first->getName();
  328. int button = boundGamepadButton.second;
  329. file << "control\t" << it->first << "\tgamepad\t" << gamepadName << "\tbutton\t" << button << '\n';
  330. }
  331. for (auto boundGamepadAxis: *boundGamepadAxes)
  332. {
  333. const std::string& gamepadName = std::get<0>(boundGamepadAxis)->getName();
  334. int axis = std::get<1>(boundGamepadAxis);
  335. bool negative = std::get<2>(boundGamepadAxis);
  336. std::stringstream axisstream;
  337. if (negative)
  338. axisstream << "-";
  339. else
  340. axisstream << "+";
  341. axisstream << axis;
  342. file << "control\t" << it->first << "\tgamepad\t" << gamepadName << "\taxis\t" << axisstream.str() << '\n';
  343. }
  344. }
  345. file.close();
  346. return true;
  347. }
  348. bool ControlProfile::load(const std::string& filename)
  349. {
  350. // Open control profile
  351. std::ifstream file(filename.c_str());
  352. if (!file.is_open())
  353. {
  354. std::cerr << "Failed to open control profile \"" << filename << "\"" << std::endl;
  355. return false;
  356. }
  357. // Read profile
  358. std::string line;
  359. while (file.good() && std::getline(file, line))
  360. {
  361. // Tokenize line (tab-delimeted)
  362. std::vector<std::string> tokens;
  363. std::string token;
  364. std::istringstream linestream(line);
  365. while (std::getline(linestream, token, '\t'))
  366. tokens.push_back(token);
  367. if (tokens.empty() || tokens[0][0] == '#')
  368. continue;
  369. if (tokens[0] == "control" && tokens.size() >= 5)
  370. {
  371. // Use control name to get control pointer
  372. auto it = controls.find(tokens[1]);
  373. if (it == controls.end())
  374. {
  375. std::cerr << "Attempted to load unregistered control \"" << tokens[1] << "\" from control profile \"" << filename << "\"" << std::endl;
  376. continue;
  377. }
  378. Control* control = it->second;
  379. // Find input device
  380. if (tokens[2] == "keyboard")
  381. {
  382. Keyboard* keyboard = inputManager->getKeyboards()->front();
  383. if (tokens[3] == "key")
  384. {
  385. std::stringstream keystream(tokens[4]);
  386. int scancode = -1;
  387. keystream >> scancode;
  388. control->bindKey(keyboard, scancode);
  389. }
  390. else
  391. {
  392. std::cerr << "Invalid line \"" << line << "\" in control profile \"" << filename << "\"" << std::endl;
  393. }
  394. }
  395. else if (tokens[2] == "mouse")
  396. {
  397. Mouse* mouse = inputManager->getMice()->front();
  398. if (tokens[3] == "button")
  399. {
  400. std::stringstream buttonstream(tokens[4]);
  401. int button = -1;
  402. buttonstream >> button;
  403. control->bindMouseButton(mouse, button);
  404. }
  405. else
  406. {
  407. std::cerr << "Invalid line \"" << line << "\" in control profile \"" << filename << "\"" << std::endl;
  408. continue;
  409. }
  410. }
  411. else if (tokens[2] == "gamepad")
  412. {
  413. if (tokens.size() != 6)
  414. {
  415. std::cerr << "Invalid line \"" << line << "\" in control profile \"" << filename << "\"" << std::endl;
  416. continue;
  417. }
  418. Gamepad* gamepad = inputManager->getGamepad(tokens[3]);
  419. if (!gamepad)
  420. {
  421. gamepad = new Gamepad(tokens[3]);
  422. gamepad->setDisconnected(true);
  423. inputManager->registerGamepad(gamepad);
  424. }
  425. if (tokens[4] == "button")
  426. {
  427. std::stringstream buttonstream(tokens[5]);
  428. int button = -1;
  429. buttonstream >> button;
  430. control->bindGamepadButton(gamepad, button);
  431. }
  432. else if (tokens[4] == "axis")
  433. {
  434. bool negative = (tokens[5][0] == '-');
  435. std::stringstream axisstream(tokens[5].substr(1, tokens[5].length() - 1));
  436. int axis = -1;
  437. axisstream >> axis;
  438. control->bindGamepadAxis(gamepad, axis, negative);
  439. }
  440. else
  441. {
  442. std::cerr << "Invalid line \"" << line << "\" in control profile \"" << filename << "\"" << std::endl;
  443. continue;
  444. }
  445. }
  446. else
  447. {
  448. std::cerr << "Unsupported input device \"" << tokens[3] << "\" in control profile \"" << filename << "\"" << std::endl;
  449. continue;
  450. }
  451. }
  452. }
  453. file.close();
  454. return true;
  455. }
  456. void ControlProfile::update()
  457. {
  458. for (auto it = controls.begin(); it != controls.end(); ++it)
  459. {
  460. it->second->update();
  461. }
  462. }