💿🐜 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.

664 lines
16 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
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. if (!boundMouseWheelAxes.empty())
  37. {
  38. currentValue = 0.0f;
  39. }
  40. previousValue = currentValue;
  41. }
  42. bool Control::isTriggered() const
  43. {
  44. return currentValue > deadzone;
  45. }
  46. bool Control::wasTriggered() const
  47. {
  48. return previousValue > deadzone;
  49. }
  50. bool Control::isUnbound() const
  51. {
  52. return (boundKeys.empty() && boundMouseButtons.empty() && boundMouseWheelAxes.empty() && boundGamepadButtons.empty() && boundGamepadAxes.empty());
  53. }
  54. void Control::bindKey(Keyboard* keyboard, int scancode)
  55. {
  56. // Check if already observing this keyboard
  57. bool observing = false;
  58. for (auto it: boundKeys)
  59. {
  60. if (it.first == keyboard)
  61. {
  62. observing = true;
  63. break;
  64. }
  65. }
  66. if (!observing)
  67. keyboard->addKeyObserver(static_cast<KeyObserver*>(this));
  68. boundKeys.push_back(std::pair<Keyboard*, int>(keyboard, scancode));
  69. }
  70. void Control::bindMouseButton(Mouse* mouse, int button)
  71. {
  72. // Checking if already observing this mouse
  73. bool observing = false;
  74. for (auto it: boundMouseButtons)
  75. {
  76. if (it.first == mouse)
  77. {
  78. observing = true;
  79. break;
  80. }
  81. }
  82. if (!observing)
  83. mouse->addMouseButtonObserver(static_cast<MouseButtonObserver*>(this));
  84. boundMouseButtons.push_back(std::pair<Mouse*, int>(mouse, button));
  85. }
  86. void Control::bindMouseWheelAxis(Mouse* mouse, MouseWheelAxis axis)
  87. {
  88. // Checking if already observing this mouse
  89. bool observing = false;
  90. for (auto it: boundMouseWheelAxes)
  91. {
  92. if (it.first == mouse)
  93. {
  94. observing = true;
  95. break;
  96. }
  97. }
  98. if (!observing)
  99. mouse->addMouseWheelObserver(static_cast<MouseWheelObserver*>(this));
  100. boundMouseWheelAxes.push_back(std::pair<Mouse*, MouseWheelAxis>(mouse, axis));
  101. }
  102. void Control::bindGamepadButton(Gamepad* gamepad, int button)
  103. {
  104. bool observing = false;
  105. for (auto it: boundGamepadButtons)
  106. {
  107. if (it.first == gamepad)
  108. {
  109. observing = true;
  110. break;
  111. }
  112. }
  113. if (!observing)
  114. gamepad->addGamepadButtonObserver(static_cast<GamepadButtonObserver*>(this));
  115. boundGamepadButtons.push_back(std::pair<Gamepad*, int>(gamepad, button));
  116. }
  117. void Control::bindGamepadAxis(Gamepad* gamepad, int axis, bool negative)
  118. {
  119. bool observing = false;
  120. for (auto it: boundGamepadAxes)
  121. {
  122. if (std::get<0>(it) == gamepad)
  123. {
  124. observing = true;
  125. break;
  126. }
  127. }
  128. if (!observing)
  129. gamepad->addGamepadAxisObserver(static_cast<GamepadAxisObserver*>(this));
  130. boundGamepadAxes.push_back(std::make_tuple(gamepad, axis, negative));
  131. }
  132. void Control::bind(const InputEvent& event)
  133. {
  134. switch (event.type)
  135. {
  136. case InputEvent::Type::KEY:
  137. bindKey(event.key.first, event.key.second);
  138. break;
  139. case InputEvent::Type::MOUSE_BUTTON:
  140. bindMouseButton(event.mouseButton.first, event.mouseButton.second);
  141. break;
  142. case InputEvent::Type::MOUSE_WHEEL:
  143. {
  144. int x = std::get<1>(event.mouseWheel);
  145. int y = std::get<2>(event.mouseWheel);
  146. MouseWheelAxis axis;
  147. if (x > 0)
  148. axis = MouseWheelAxis::POSITIVE_X;
  149. else if (x < 0)
  150. axis = MouseWheelAxis::NEGATIVE_X;
  151. else if (y > 0)
  152. axis = MouseWheelAxis::POSITIVE_Y;
  153. else if (y < 0)
  154. axis = MouseWheelAxis::NEGATIVE_Y;
  155. else
  156. break;
  157. bindMouseWheelAxis(std::get<0>(event.mouseWheel), axis);
  158. break;
  159. }
  160. case InputEvent::Type::GAMEPAD_BUTTON:
  161. bindGamepadButton(event.gamepadButton.first, event.gamepadButton.second);
  162. break;
  163. case InputEvent::Type::GAMEPAD_AXIS:
  164. bindGamepadAxis(std::get<0>(event.gamepadAxis), std::get<1>(event.gamepadAxis), std::get<2>(event.gamepadAxis));
  165. break;
  166. default:
  167. break;
  168. }
  169. }
  170. void Control::unbind()
  171. {
  172. while (!boundKeys.empty())
  173. {
  174. // Remove the first bound key and stop observing its keyboard
  175. Keyboard* keyboard = boundKeys.front().first;
  176. keyboard->removeKeyObserver(static_cast<KeyObserver*>(this));
  177. boundKeys.pop_front();
  178. // Remove other bound keys which are associated with the keyboard
  179. auto it = boundKeys.begin();
  180. while (it != boundKeys.end())
  181. {
  182. if (it->first == keyboard)
  183. boundKeys.erase(it++);
  184. else
  185. ++it;
  186. }
  187. }
  188. while (!boundMouseButtons.empty())
  189. {
  190. // Remove the first bound mouse button and stop observing its mouse
  191. Mouse* mouse = boundMouseButtons.front().first;
  192. mouse->removeMouseButtonObserver(static_cast<MouseButtonObserver*>(this));
  193. boundMouseButtons.pop_front();
  194. // Remove other bound mouse buttons which are associated with the mouse
  195. auto it = boundMouseButtons.begin();
  196. while (it != boundMouseButtons.end())
  197. {
  198. if (it->first == mouse)
  199. boundMouseButtons.erase(it++);
  200. else
  201. ++it;
  202. }
  203. }
  204. while (!boundMouseWheelAxes.empty())
  205. {
  206. // Remove the first bound mouse button and stop observing its mouse
  207. Mouse* mouse = boundMouseWheelAxes.front().first;
  208. mouse->removeMouseWheelObserver(static_cast<MouseWheelObserver*>(this));
  209. boundMouseWheelAxes.pop_front();
  210. // Remove other bound mouse buttons which are associated with the mouse
  211. auto it = boundMouseWheelAxes.begin();
  212. while (it != boundMouseWheelAxes.end())
  213. {
  214. if (it->first == mouse)
  215. boundMouseWheelAxes.erase(it++);
  216. else
  217. ++it;
  218. }
  219. }
  220. while (!boundGamepadButtons.empty())
  221. {
  222. // Remove the first bound gamepad button and stop observing its gamepad
  223. Gamepad* gamepad = boundGamepadButtons.front().first;
  224. gamepad->removeGamepadButtonObserver(static_cast<GamepadButtonObserver*>(this));
  225. boundGamepadButtons.pop_front();
  226. // Remove other bound gamepad buttons which are associated with the gamepad
  227. auto it = boundGamepadButtons.begin();
  228. while (it != boundGamepadButtons.end())
  229. {
  230. if (it->first == gamepad)
  231. boundGamepadButtons.erase(it++);
  232. else
  233. ++it;
  234. }
  235. }
  236. while (!boundGamepadAxes.empty())
  237. {
  238. // Remove the first bound gamepad axis and stop observing its gamepad
  239. Gamepad* gamepad = std::get<0>(boundGamepadAxes.front());
  240. gamepad->removeGamepadAxisObserver(static_cast<GamepadAxisObserver*>(this));
  241. boundGamepadAxes.pop_front();
  242. // Remove other bound gamepad axes which are associated with the gamepad
  243. auto it = boundGamepadAxes.begin();
  244. while (it != boundGamepadAxes.end())
  245. {
  246. if (std::get<0>(*it) == gamepad)
  247. boundGamepadAxes.erase(it++);
  248. else
  249. ++it;
  250. }
  251. }
  252. }
  253. void Control::keyPressed(int scancode)
  254. {
  255. for (auto it: boundKeys)
  256. {
  257. if (it.second == scancode)
  258. {
  259. currentValue = 1.0f;
  260. break;
  261. }
  262. }
  263. }
  264. void Control::keyReleased(int scancode)
  265. {
  266. for (auto it: boundKeys)
  267. {
  268. if (it.second == scancode)
  269. {
  270. currentValue = 0.0f;
  271. break;
  272. }
  273. }
  274. }
  275. void Control::mouseButtonPressed(int button, int x, int y)
  276. {
  277. for (auto it: boundMouseButtons)
  278. {
  279. if (it.second == button)
  280. {
  281. currentValue = 1.0f;
  282. break;
  283. }
  284. }
  285. }
  286. void Control::mouseButtonReleased(int button, int x, int y)
  287. {
  288. for (auto it: boundMouseButtons)
  289. {
  290. if (it.second == button)
  291. {
  292. currentValue = 0.0f;
  293. break;
  294. }
  295. }
  296. }
  297. void Control::mouseWheelScrolled(int x, int y)
  298. {
  299. for (auto it: boundMouseWheelAxes)
  300. {
  301. if (it.second == MouseWheelAxis::POSITIVE_X && x > 0)
  302. {
  303. currentValue += x;
  304. break;
  305. }
  306. else if (it.second == MouseWheelAxis::NEGATIVE_X && x < 0)
  307. {
  308. currentValue -= x;
  309. break;
  310. }
  311. else if (it.second == MouseWheelAxis::POSITIVE_Y && y > 0)
  312. {
  313. currentValue += y;
  314. break;
  315. }
  316. else if (it.second == MouseWheelAxis::NEGATIVE_Y && y < 0)
  317. {
  318. currentValue -= y;
  319. break;
  320. }
  321. }
  322. }
  323. void Control::gamepadButtonPressed(int button)
  324. {
  325. for (auto it: boundGamepadButtons)
  326. {
  327. if (it.second == button)
  328. {
  329. currentValue = 1.0f;
  330. break;
  331. }
  332. }
  333. }
  334. void Control::gamepadButtonReleased(int button)
  335. {
  336. for (auto it: boundGamepadButtons)
  337. {
  338. if (it.second == button)
  339. {
  340. currentValue = 0.0f;
  341. break;
  342. }
  343. }
  344. }
  345. void Control::gamepadAxisMoved(int axis, bool negative, float value)
  346. {
  347. for (auto it: boundGamepadAxes)
  348. {
  349. if (std::get<1>(it) == axis && std::get<2>(it) == negative)
  350. {
  351. currentValue = value;
  352. break;
  353. }
  354. }
  355. }
  356. const std::list<std::pair<Keyboard*, int>>* Control::getBoundKeys() const
  357. {
  358. return &boundKeys;
  359. }
  360. const std::list<std::pair<Mouse*, int>>* Control::getBoundMouseButtons() const
  361. {
  362. return &boundMouseButtons;
  363. }
  364. const std::list<std::pair<Mouse*, MouseWheelAxis>>* Control::getBoundMouseWheelAxes() const
  365. {
  366. return &boundMouseWheelAxes;
  367. }
  368. const std::list<std::pair<Gamepad*, int>>* Control::getBoundGamepadButtons() const
  369. {
  370. return &boundGamepadButtons;
  371. }
  372. const std::list<std::tuple<Gamepad*, int, bool>>* Control::getBoundGamepadAxes() const
  373. {
  374. return &boundGamepadAxes;
  375. }
  376. ControlProfile::ControlProfile(InputManager* inputManager):
  377. inputManager(inputManager)
  378. {}
  379. void ControlProfile::registerControl(const std::string& name, Control* control)
  380. {
  381. controls[name] = control;
  382. }
  383. bool ControlProfile::save(const std::string& filename)
  384. {
  385. // Open control profile
  386. std::ofstream file(filename.c_str());
  387. if (!file.is_open())
  388. {
  389. std::cerr << std::string("Failed to open control profile \"") << filename << std::string("\"") << std::endl;
  390. return false;
  391. }
  392. for (auto it = controls.begin(); it != controls.end(); ++it)
  393. {
  394. Control* control = it->second;
  395. const std::list<std::pair<Keyboard*, int>>* boundKeys = control->getBoundKeys();
  396. const std::list<std::pair<Mouse*, int>>* boundMouseButtons = control->getBoundMouseButtons();
  397. const std::list<std::pair<Mouse*, MouseWheelAxis>>* boundMouseWheelAxes = control->getBoundMouseWheelAxes();
  398. const std::list<std::pair<Gamepad*, int>>* boundGamepadButtons = control->getBoundGamepadButtons();
  399. const std::list<std::tuple<Gamepad*, int, bool>>* boundGamepadAxes = control->getBoundGamepadAxes();
  400. for (auto boundKey: *boundKeys)
  401. {
  402. int key = boundKey.second;
  403. file << std::string("control\t") << it->first << std::string("\tkeyboard\tkey\t") << key << '\n';
  404. }
  405. for (auto boundMouseButton: *boundMouseButtons)
  406. {
  407. int button = boundMouseButton.second;
  408. file << std::string("control\t") << it->first << std::string("\tmouse\tbutton\t") << button << '\n';
  409. }
  410. for (auto boundMouseWheelAxis: *boundMouseWheelAxes)
  411. {
  412. MouseWheelAxis axis = boundMouseWheelAxis.second;
  413. file << std::string("control\t") << it->first << std::string("\tmouse\twheel\t");
  414. if (axis == MouseWheelAxis::POSITIVE_X)
  415. file << std::string("+x");
  416. else if (axis == MouseWheelAxis::NEGATIVE_X)
  417. file << std::string("-x");
  418. else if (axis == MouseWheelAxis::POSITIVE_Y)
  419. file << std::string("+y");
  420. else if (axis == MouseWheelAxis::NEGATIVE_Y)
  421. file << std::string("-y");
  422. else
  423. file << std::string("unknown");
  424. file << '\n';
  425. }
  426. for (auto boundGamepadButton: *boundGamepadButtons)
  427. {
  428. const std::string& gamepadName = boundGamepadButton.first->getName();
  429. int button = boundGamepadButton.second;
  430. file << std::string("control\t") << it->first << std::string("\tgamepad\t") << gamepadName << std::string("\tbutton\t") << button << '\n';
  431. }
  432. for (auto boundGamepadAxis: *boundGamepadAxes)
  433. {
  434. const std::string& gamepadName = std::get<0>(boundGamepadAxis)->getName();
  435. int axis = std::get<1>(boundGamepadAxis);
  436. bool negative = std::get<2>(boundGamepadAxis);
  437. std::stringstream axisstream;
  438. if (negative)
  439. axisstream << std::string("-");
  440. else
  441. axisstream << std::string("+");
  442. axisstream << axis;
  443. file << std::string("control\t") << it->first << std::string("\tgamepad\t") << gamepadName << std::string("\taxis\t") << axisstream.str() << '\n';
  444. }
  445. }
  446. file.close();
  447. return true;
  448. }
  449. bool ControlProfile::load(const std::string& filename)
  450. {
  451. // Open control profile
  452. std::ifstream file(filename.c_str());
  453. if (!file.is_open())
  454. {
  455. std::cerr << std::string("Failed to open control profile \"") << filename << std::string("\"") << std::endl;
  456. return false;
  457. }
  458. // Read profile
  459. std::string line;
  460. while (file.good() && std::getline(file, line))
  461. {
  462. // Tokenize line (tab-delimeted)
  463. std::vector<std::string> tokens;
  464. std::string token;
  465. std::istringstream linestream(line);
  466. while (std::getline(linestream, token, '\t'))
  467. tokens.push_back(token);
  468. if (tokens.empty() || tokens[0][0] == '#')
  469. continue;
  470. if (tokens[0] == "control" && tokens.size() >= 5)
  471. {
  472. // Use control name to get control pointer
  473. auto it = controls.find(tokens[1]);
  474. if (it == controls.end())
  475. {
  476. std::cerr << std::string("Attempted to load unregistered control \"") << tokens[1] << std::string("\" from control profile \"") << filename << std::string("\"") << std::endl;
  477. continue;
  478. }
  479. Control* control = it->second;
  480. // Find input device
  481. if (tokens[2] == "keyboard")
  482. {
  483. Keyboard* keyboard = inputManager->getKeyboards()->front();
  484. if (tokens[3] == "key")
  485. {
  486. std::stringstream keystream(tokens[4]);
  487. int scancode = -1;
  488. keystream >> scancode;
  489. control->bindKey(keyboard, scancode);
  490. }
  491. else
  492. {
  493. std::cerr << std::string("Invalid line \"") << line << std::string("\" in control profile \"") << filename << std::string("\"") << std::endl;
  494. }
  495. }
  496. else if (tokens[2] == "mouse")
  497. {
  498. Mouse* mouse = inputManager->getMice()->front();
  499. if (tokens[3] == "button")
  500. {
  501. std::stringstream buttonstream(tokens[4]);
  502. int button = -1;
  503. buttonstream >> button;
  504. control->bindMouseButton(mouse, button);
  505. }
  506. else if (tokens[3] == "wheel")
  507. {
  508. MouseWheelAxis axis;
  509. if (tokens[4] == "+x")
  510. axis = MouseWheelAxis::POSITIVE_X;
  511. else if (tokens[4] == "-x")
  512. axis = MouseWheelAxis::NEGATIVE_X;
  513. else if (tokens[4] == "+y")
  514. axis = MouseWheelAxis::POSITIVE_Y;
  515. else if (tokens[4] == "-y")
  516. axis = MouseWheelAxis::NEGATIVE_Y;
  517. else
  518. {
  519. std::cerr << std::string("Invalid line \"") << line << std::string("\" in control profile \"") << filename << std::string("\"") << std::endl;
  520. continue;
  521. }
  522. control->bindMouseWheelAxis(mouse, axis);
  523. }
  524. else
  525. {
  526. std::cerr << std::string("Invalid line \"") << line << std::string("\" in control profile \"") << filename << std::string("\"") << std::endl;
  527. continue;
  528. }
  529. }
  530. else if (tokens[2] == "gamepad")
  531. {
  532. if (tokens.size() != 6)
  533. {
  534. std::cerr << std::string("Invalid line \"") << line << std::string("\" in control profile \"") << filename << std::string("\"") << std::endl;
  535. continue;
  536. }
  537. Gamepad* gamepad = inputManager->getGamepad(tokens[3]);
  538. if (!gamepad)
  539. {
  540. gamepad = new Gamepad(tokens[3]);
  541. gamepad->setDisconnected(true);
  542. inputManager->registerGamepad(gamepad);
  543. }
  544. if (tokens[4] == "button")
  545. {
  546. std::stringstream buttonstream(tokens[5]);
  547. int button = -1;
  548. buttonstream >> button;
  549. control->bindGamepadButton(gamepad, button);
  550. }
  551. else if (tokens[4] == "axis")
  552. {
  553. bool negative = (tokens[5][0] == '-');
  554. std::stringstream axisstream(tokens[5].substr(1, tokens[5].length() - 1));
  555. int axis = -1;
  556. axisstream >> axis;
  557. control->bindGamepadAxis(gamepad, axis, negative);
  558. }
  559. else
  560. {
  561. std::cerr << std::string("Invalid line \"") << line << std::string("\" in control profile \"") << filename << std::string("\"") << std::endl;
  562. continue;
  563. }
  564. }
  565. else
  566. {
  567. std::cerr << std::string("Unsupported input device \"") << tokens[3] << std::string("\" in control profile \"") << filename << std::string("\"") << std::endl;
  568. continue;
  569. }
  570. }
  571. }
  572. file.close();
  573. return true;
  574. }
  575. void ControlProfile::update()
  576. {
  577. for (auto it = controls.begin(); it != controls.end(); ++it)
  578. {
  579. it->second->update();
  580. }
  581. }