--- /dev/null
+#ifndef MSP_GAMEVIEW_PLAYERINPUT_H_
+#define MSP_GAMEVIEW_PLAYERINPUT_H_
+
+#include <memory>
+#include <msp/input/bindings.h>
+#include <msp/input/controlscheme.h>
+#include <msp/input/hub.h>
+#include <msp/input/keyboard.h>
+#include <msp/input/mouse.h>
+#include <msp/game/director.h>
+#include "events.h"
+
+namespace Msp::GameView {
+
+class PlayerInput: public NonCopyable
+{
+public:
+ using EventSource = Game::EventSource<Events::PlayerArrived, Events::PlayerDeparted>;
+
+ enum Mode
+ {
+ ONE_LOCAL_PLAYER,
+ LOCAL_MULTIPLAYER
+ };
+
+private:
+ struct Player
+ {
+ Input::Device *device = nullptr;
+ std::unique_ptr<Input::ControlScheme> controls = nullptr;
+ };
+
+ using SchemeFactoryFunc = std::unique_ptr<Input::ControlScheme>();
+
+ EventSource event_source;
+ Input::Keyboard keyboard;
+ Input::Mouse mouse;
+ Input::Hub kbm_hub;
+ std::vector<Input::Bindings *> bindings;
+ SchemeFactoryFunc *scheme_factory = nullptr;
+ std::vector<Player> players;
+ Mode mode = ONE_LOCAL_PLAYER;
+
+public:
+ PlayerInput(Game::Director &, Graphics::Window &);
+
+ template<typename T>
+ requires std::is_base_of_v<Input::ControlScheme, T>
+ void set_control_scheme_type(Mode = ONE_LOCAL_PLAYER);
+
+private:
+ void init_players();
+ void add_player(Input::Device &);
+
+public:
+ void synthesize_initial_events(Game::EventObserver &);
+};
+
+
+template<typename T>
+ requires std::is_base_of_v<Input::ControlScheme, T>
+void PlayerInput::set_control_scheme_type(Mode m)
+{
+ if(scheme_factory)
+ throw std::logic_error("scheme type already set");
+
+ mode = m;
+ scheme_factory = +[]() -> std::unique_ptr<Input::ControlScheme> { return std::make_unique<T>(); };
+ init_players();
+}
+
+} // namespace Msp::GameView
+
+#endif