summaryrefslogtreecommitdiff
path: root/lib/nes/app/input/input-manager.cc
blob: 1c9db9e2a4473f494d9a1f6d5db1abf152c96725 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include "nes/app/input/input-manager.hh"

namespace nes
{
	namespace
	{
		class input_device_dummy final : public input_device
		{
		public:
			explicit input_device_dummy() = default;

			static auto get_instance() -> input_device_dummy&
			{
				static auto res = input_device_dummy{};
				return res;
			}

			auto read_key_up() -> bool override { return false; }
			auto read_key_down() -> bool override { return false; }
			auto read_key_left() -> bool override { return false; }
			auto read_key_right() -> bool override { return false; }
			auto read_key_a() -> bool override { return false; }
			auto read_key_b() -> bool override { return false; }
			auto read_key_select() -> bool override { return false; }
			auto read_key_start() -> bool override { return false; }
		};
	} // namespace

	input_manager::input_manager(input_device_keyboard& keyboard)
		: keyboard_{ &keyboard }
	{
		fill_unassigned_inputs();
	}

	auto input_manager::add_controller(input_device_controller& controller) -> void
	{
		controllers_.append(controller);
		if (controller.is_reliable())
		{
			auto const index = controller.get_index();
			if (index != input_device_controller::index::unused)
			{
				// This controller was previously used and assigned an index -> replace the current device with this
				// (known) controller.
				auto const i = static_cast<std::size_t>(index);
				if (inputs_[i].controller)
				{
					inputs_[i].controller->set_index(input_device_controller::index::unused);
				}

				inputs_[i].controller = &controller;
				inputs_[i].device = &controller;
			}

			// There may be another free controller now.
			fill_unassigned_inputs();
		}
	}

	auto input_manager::remove_controller(input_device_controller& controller) -> void
	{
		controllers_.remove(controller);
		fill_unassigned_inputs();
	}

	auto input_manager::fill_unassigned_inputs() -> void
	{
		auto it = controllers_.begin();
		input_device* fallback = keyboard_;

		for (auto i = std::size_t{ 0 }; i < input_count; ++i)
		{
			if (inputs_[i].controller != nullptr) { continue; }

			// This input is not assigned -> use the next available controller if available.
			while (it != controllers_.end())
			{
				auto controller = *it;
				if (controller->is_reliable() && controller->get_index() == input_device_controller::index::unused)
				{
					break;
				}
				++it;
			}

			if (it != controllers_.end())
			{
				// We've found an unused controller -> assign it.
				inputs_[i].controller = *it;
				inputs_[i].controller->set_index(static_cast<input_device_controller::index>(i));
				inputs_[i].device = *it;
			}
			else
			{
				// We're all out of controllers -> fall back to the keyboard (if this is the first missing controller)
				// or nothing.
				inputs_[i].device = fallback;
				fallback = &input_device_dummy::get_instance(); // Only use the keyboard as a fallback once.
			}
		}
	}
} // namespace nes