Browse Source

Add control configuration support

master
C. J. Howard 2 years ago
parent
commit
2cfa33d934
9 changed files with 703 additions and 163 deletions
  1. +19
    -1
      src/event/event-dispatcher.cpp
  2. +17
    -15
      src/event/event-dispatcher.hpp
  3. +0
    -71
      src/game/context.hpp
  4. +0
    -8
      src/game/states/boot.cpp
  5. +305
    -2
      src/game/states/controller-config-menu.cpp
  6. +259
    -7
      src/game/states/keyboard-config-menu.cpp
  7. +55
    -0
      src/input/event-router.cpp
  8. +13
    -4
      src/input/event-router.hpp
  9. +35
    -55
      src/input/listener.cpp

+ 19
- 1
src/event/event-dispatcher.cpp View File

@ -19,7 +19,8 @@
#include "event-dispatcher.hpp" #include "event-dispatcher.hpp"
event_dispatcher::event_dispatcher()
event_dispatcher::event_dispatcher():
updating(false)
{} {}
event_dispatcher::~event_dispatcher() event_dispatcher::~event_dispatcher()
@ -29,6 +30,8 @@ event_dispatcher::~event_dispatcher()
void event_dispatcher::update(double time) void event_dispatcher::update(double time)
{ {
updating = true;
// Process pending subscriptions // Process pending subscriptions
for (auto it = to_subscribe.begin(); it != to_subscribe.end(); ++it) for (auto it = to_subscribe.begin(); it != to_subscribe.end(); ++it)
{ {
@ -64,6 +67,21 @@ void event_dispatcher::update(double time)
break; break;
} }
} }
updating = false;
}
void event_dispatcher::dispatch(const event_base& event)
{
// Get list of handlers for this type of event
const std::list<event_handler_base*>& handlers = handler_map[event.get_event_type_id()];
// For each handler
for (auto handler = handlers.begin(); handler != handlers.end(); ++handler)
{
// Pass event to the handler
(*handler)->route_event(event);
}
} }
void event_dispatcher::flush() void event_dispatcher::flush()

+ 17
- 15
src/event/event-dispatcher.hpp View File

@ -97,18 +97,33 @@ private:
std::map<std::size_t, std::list<event_handler_base*>> handler_map; std::map<std::size_t, std::list<event_handler_base*>> handler_map;
std::list<event_base*> queued_events; std::list<event_base*> queued_events;
std::multimap<double, event_base*> scheduled_events; std::multimap<double, event_base*> scheduled_events;
bool updating;
}; };
template <typename T> template <typename T>
void event_dispatcher::subscribe(event_handler<T>* handler) void event_dispatcher::subscribe(event_handler<T>* handler)
{ {
to_subscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler));
if (updating)
{
to_subscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler));
}
else
{
handler_map[handler->get_handled_event_type_id()].push_back(handler);
}
} }
template <typename T> template <typename T>
void event_dispatcher::unsubscribe(event_handler<T>* handler) void event_dispatcher::unsubscribe(event_handler<T>* handler)
{ {
to_unsubscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler));
if (updating)
{
to_unsubscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler));
}
else
{
handler_map[handler->get_handled_event_type_id()].remove(handler);
}
} }
inline void event_dispatcher::queue(const event_base& event) inline void event_dispatcher::queue(const event_base& event)
@ -121,18 +136,5 @@ inline void event_dispatcher::schedule(const event_base& event, double time)
scheduled_events.insert(std::pair<double, event_base*>(time, event.clone())); scheduled_events.insert(std::pair<double, event_base*>(time, event.clone()));
} }
inline void event_dispatcher::dispatch(const event_base& event)
{
// Get list of handlers for this type of event
const std::list<event_handler_base*>& handlers = handler_map[event.get_event_type_id()];
// For each handler
for (auto handler = handlers.begin(); handler != handlers.end(); ++handler)
{
// Pass event to the handler
(*handler)->route_event(event);
}
}
#endif // ANTKEEPER_EVENT_DISPATCHER_HPP #endif // ANTKEEPER_EVENT_DISPATCHER_HPP

+ 0
- 71
src/game/context.hpp View File

@ -205,81 +205,10 @@ struct context
scene::billboard* camera_flash_billboard; scene::billboard* camera_flash_billboard;
scene::text* title_text; scene::text* title_text;
scene::text* title_press_any_key_text; scene::text* title_press_any_key_text;
scene::text* main_menu_start_text;
scene::text* main_menu_options_text;
scene::text* main_menu_credits_text;
scene::text* main_menu_quit_text;
std::vector<scene::text*> main_menu_texts;
int main_menu_index;
scene::text* credits_text; scene::text* credits_text;
scene::text* options_menu_controls_text;
scene::text* options_menu_graphics_text;
scene::text* options_menu_sound_text;
scene::text* options_menu_language_text;
scene::text* options_menu_back_text;
std::vector<scene::text*> options_menu_texts;
std::vector<std::function<void()>> options_menu_callbacks;
int options_menu_index;
scene::text* controls_menu_configure_keyboard_mouse_label_text;
scene::text* controls_menu_configure_game_controller_label_text;
scene::text* controls_menu_back_label_text;
std::vector<scene::text*> controls_menu_label_texts;
std::vector<scene::text*> controls_menu_value_texts;
int controls_menu_index;
std::vector<std::function<void()>> controls_menu_select_callbacks;
std::vector<std::function<void()>> controls_menu_left_callbacks;
std::vector<std::function<void()>> controls_menu_right_callbacks;
scene::text* language_menu_language_text;
scene::text* language_menu_back_text;
std::vector<scene::text*> language_menu_texts;
std::vector<std::function<void()>> language_menu_callbacks;
int language_menu_index;
scene::text* sound_menu_master_volume_label_text;
scene::text* sound_menu_master_volume_value_text;
scene::text* sound_menu_ambience_volume_label_text;
scene::text* sound_menu_ambience_volume_value_text;
scene::text* sound_menu_effects_volume_label_text;
scene::text* sound_menu_effects_volume_value_text;
scene::text* sound_menu_mono_audio_label_text;
scene::text* sound_menu_mono_audio_value_text;
scene::text* sound_menu_captions_label_text;
scene::text* sound_menu_captions_value_text;
scene::text* sound_menu_captions_size_label_text;
scene::text* sound_menu_captions_size_value_text;
scene::text* sound_menu_back_label_text;
std::vector<scene::text*> sound_menu_label_texts;
std::vector<scene::text*> sound_menu_value_texts;
int sound_menu_index;
std::vector<std::function<void()>> sound_menu_select_callbacks;
std::vector<std::function<void()>> sound_menu_left_callbacks;
std::vector<std::function<void()>> sound_menu_right_callbacks;
scene::text* graphics_menu_display_mode_label_text;
scene::text* graphics_menu_display_mode_value_text;
scene::text* graphics_menu_render_resolution_label_text;
scene::text* graphics_menu_render_resolution_value_text;
scene::text* graphics_menu_v_sync_label_text;
scene::text* graphics_menu_v_sync_value_text;
scene::text* graphics_menu_font_size_label_text;
scene::text* graphics_menu_font_size_value_text;
scene::text* graphics_menu_dyslexia_font_label_text;
scene::text* graphics_menu_dyslexia_font_value_text;
scene::text* graphics_menu_back_label_text;
std::vector<scene::text*> graphics_menu_label_texts;
std::vector<scene::text*> graphics_menu_value_texts;
int graphics_menu_index;
std::vector<std::function<void()>> graphics_menu_select_callbacks;
std::vector<std::function<void()>> graphics_menu_left_callbacks;
std::vector<std::function<void()>> graphics_menu_right_callbacks;
std::vector<scene::text*> keyboard_config_menu_label_texts;
std::vector<scene::text*> keyboard_config_menu_value_texts;
int keyboard_config_menu_index;
std::vector<std::function<void()>> keyboard_config_menu_select_callbacks;
std::vector<std::function<void()>> keyboard_config_menu_left_callbacks;
std::vector<std::function<void()>> keyboard_config_menu_right_callbacks;
float font_size; float font_size;
bool dyslexia_font; bool dyslexia_font;
ui::mouse_tracker* menu_mouse_tracker; ui::mouse_tracker* menu_mouse_tracker;
std::vector<std::function<void()>> menu_select_callbacks; std::vector<std::function<void()>> menu_select_callbacks;
std::vector<std::function<void()>> menu_left_callbacks; std::vector<std::function<void()>> menu_left_callbacks;
std::vector<std::function<void()>> menu_right_callbacks; std::vector<std::function<void()>> menu_right_callbacks;

+ 0
- 8
src/game/states/boot.cpp View File

@ -1004,14 +1004,6 @@ void setup_ui(game::context* ctx)
if (ctx->config->contains("dyslexia_font")) if (ctx->config->contains("dyslexia_font"))
ctx->dyslexia_font = (*ctx->config)["dyslexia_font"].get<bool>(); ctx->dyslexia_font = (*ctx->config)["dyslexia_font"].get<bool>();
ctx->main_menu_index = 0;
ctx->options_menu_index = 0;
ctx->controls_menu_index = 0;
ctx->graphics_menu_index = 0;
ctx->sound_menu_index = 0;
ctx->language_menu_index = 0;
ctx->keyboard_config_menu_index = 0;
// Construct mouse tracker // Construct mouse tracker
ctx->menu_mouse_tracker = new ui::mouse_tracker(); ctx->menu_mouse_tracker = new ui::mouse_tracker();
ctx->app->get_event_dispatcher()->subscribe<mouse_moved_event>(ctx->menu_mouse_tracker); ctx->app->get_event_dispatcher()->subscribe<mouse_moved_event>(ctx->menu_mouse_tracker);

+ 305
- 2
src/game/states/controller-config-menu.cpp View File

@ -23,19 +23,322 @@
#include "scene/text.hpp" #include "scene/text.hpp"
#include "render/passes/clear-pass.hpp" #include "render/passes/clear-pass.hpp"
#include "debug/logger.hpp" #include "debug/logger.hpp"
#include "resources/resource-manager.hpp"
#include "game/menu.hpp"
#include "animation/timeline.hpp"
namespace game { namespace game {
namespace state { namespace state {
namespace controller_config_menu { namespace controller_config_menu {
void enter(game::context* ctx)
static std::string get_binding_string(game::context* ctx, input::control* control)
{ {
std::string binding_string;
auto mappings = ctx->input_event_router->get_mappings(control);
for (input::mapping* mapping: *mappings)
{
std::string mapping_string;
switch (mapping->get_type())
{
case input::mapping_type::gamepad_axis:
{
const input::gamepad_axis_mapping* axis_mapping = static_cast<const input::gamepad_axis_mapping*>(mapping);
switch (axis_mapping->axis)
{
case input::gamepad_axis::left_x:
if (axis_mapping->negative)
mapping_string = (*ctx->strings)["gamepad_left_stick_left"];
else
mapping_string = (*ctx->strings)["gamepad_left_stick_right"];
break;
case input::gamepad_axis::left_y:
if (axis_mapping->negative)
mapping_string = (*ctx->strings)["gamepad_left_stick_up"];
else
mapping_string = (*ctx->strings)["gamepad_left_stick_down"];
break;
case input::gamepad_axis::right_x:
if (axis_mapping->negative)
mapping_string = (*ctx->strings)["gamepad_right_stick_left"];
else
mapping_string = (*ctx->strings)["gamepad_right_stick_right"];
break;
case input::gamepad_axis::right_y:
if (axis_mapping->negative)
mapping_string = (*ctx->strings)["gamepad_right_stick_up"];
else
mapping_string = (*ctx->strings)["gamepad_right_stick_down"];
break;
case input::gamepad_axis::left_trigger:
mapping_string = (*ctx->strings)["gamepad_left_trigger"];
break;
case input::gamepad_axis::right_trigger:
mapping_string = (*ctx->strings)["gamepad_right_trigger"];
break;
default:
break;
}
break;
}
case input::mapping_type::gamepad_button:
{
const input::gamepad_button_mapping* button_mapping = static_cast<const input::gamepad_button_mapping*>(mapping);
switch (button_mapping->button)
{
case input::gamepad_button::a:
mapping_string = (*ctx->strings)["gamepad_button_a"];
break;
case input::gamepad_button::b:
mapping_string = (*ctx->strings)["gamepad_button_b"];
break;
case input::gamepad_button::x:
mapping_string = (*ctx->strings)["gamepad_button_x"];
break;
case input::gamepad_button::y:
mapping_string = (*ctx->strings)["gamepad_button_y"];
break;
case input::gamepad_button::back:
mapping_string = (*ctx->strings)["gamepad_button_back"];
break;
case input::gamepad_button::guide:
mapping_string = (*ctx->strings)["gamepad_button_guide"];
break;
case input::gamepad_button::start:
mapping_string = (*ctx->strings)["gamepad_button_start"];
break;
case input::gamepad_button::left_stick:
mapping_string = (*ctx->strings)["gamepad_button_left_stick"];
break;
case input::gamepad_button::right_stick:
mapping_string = (*ctx->strings)["gamepad_button_right_stick"];
break;
case input::gamepad_button::left_shoulder:
mapping_string = (*ctx->strings)["gamepad_button_left_shoulder"];
break;
case input::gamepad_button::right_shoulder:
mapping_string = (*ctx->strings)["gamepad_button_right_shoulder"];
break;
case input::gamepad_button::dpad_up:
mapping_string = (*ctx->strings)["gamepad_button_dpad_up"];
break;
case input::gamepad_button::dpad_down:
mapping_string = (*ctx->strings)["gamepad_button_dpad_down"];
break;
case input::gamepad_button::dpad_left:
mapping_string = (*ctx->strings)["gamepad_button_dpad_left"];
break;
case input::gamepad_button::dpad_right:
mapping_string = (*ctx->strings)["gamepad_button_dpad_right"];
break;
default:
break;
}
break;
}
default:
break;
}
if (!mapping_string.empty())
{
if (binding_string.empty())
{
binding_string = mapping_string;
}
else
{
binding_string += " " + mapping_string;
}
}
}
return binding_string;
}
static void add_control_item(game::context* ctx, const std::string& control_name)
{
// Get pointer to control
input::control* control = ctx->controls[control_name];
// Construct texts
scene::text* name_text = new scene::text();
scene::text* value_text = new scene::text();
// Add texts to list of menu item texts
ctx->menu_item_texts.push_back({name_text, value_text});
// Set content of name text
std::string string_name = "control_" + control_name;
if (auto it = ctx->strings->find(string_name); it != ctx->strings->end())
name_text->set_content(it->second);
else
name_text->set_content(control_name);
// Set content of value text
value_text->set_content(get_binding_string(ctx, control));
auto select_callback = [ctx, control, value_text]()
{
// Clear binding string from value text
value_text->set_content((*ctx->strings)["ellipsis"]);
game::menu::align_text(ctx);
game::menu::update_text_tweens(ctx);
// Disable controls
game::menu::clear_controls(ctx);
// Remove gamepad event mappings from control
ctx->input_event_router->remove_mappings(control, input::mapping_type::gamepad_axis);
ctx->input_event_router->remove_mappings(control, input::mapping_type::gamepad_button);
// Setup input binding listener
ctx->input_listener->set_callback
(
[ctx, control, value_text](const event_base& event)
{
auto id = event.get_event_type_id();
if (id == gamepad_axis_moved_event::event_type_id)
{
// Map gamepad axis event to control
const gamepad_axis_moved_event& axis_event = static_cast<const gamepad_axis_moved_event&>(event);
if (std::abs(axis_event.value) < 0.5f)
return;
ctx->input_event_router->add_mapping(input::gamepad_axis_mapping(control, nullptr, axis_event.axis, (axis_event.value < 0)));
}
else if (id == gamepad_button_pressed_event::event_type_id)
{
// Map gamepad button event to control
const gamepad_button_pressed_event& button_event = static_cast<const gamepad_button_pressed_event&>(event);
ctx->input_event_router->add_mapping(input::gamepad_button_mapping(control, nullptr, button_event.button));
}
else
{
return;
}
// Update menu text
value_text->set_content(get_binding_string(ctx, control));
game::menu::align_text(ctx);
game::menu::update_text_tweens(ctx);
// Disable input listener
ctx->input_listener->set_enabled(false);
ctx->input_listener->set_callback(nullptr);
// Schedule re-enabling of menu controls
timeline* timeline = ctx->timeline;
float t = timeline->get_position();
timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}});
}
);
ctx->input_listener->set_enabled(true);
};
// Register menu item callbacks
ctx->menu_select_callbacks.push_back(select_callback);
ctx->menu_left_callbacks.push_back(nullptr);
ctx->menu_right_callbacks.push_back(nullptr);
} }
void exit(game::context* ctx)
void enter(game::context* ctx)
{ {
ctx->ui_clear_pass->set_cleared_buffers(true, true, false);
// Add camera control menu items
add_control_item(ctx, "dolly_forward");
add_control_item(ctx, "dolly_backward");
add_control_item(ctx, "truck_left");
add_control_item(ctx, "truck_right");
add_control_item(ctx, "pedestal_up");
add_control_item(ctx, "pedestal_down");
// Add application control menu items
add_control_item(ctx, "toggle_fullscreen");
add_control_item(ctx, "screenshot");
// Construct menu item texts
scene::text* back_text = new scene::text();
// Build list of menu item texts
ctx->menu_item_texts.push_back({back_text, nullptr});
// Set content of menu item texts
back_text->set_content((*ctx->strings)["back"]);
// Init menu item index
game::menu::init_menu_item_index(ctx, "controller_config");
game::menu::update_text_color(ctx);
game::menu::update_text_font(ctx);
game::menu::align_text(ctx);
game::menu::update_text_tweens(ctx);
game::menu::add_text_to_ui(ctx);
// Construct menu item callbacks
auto select_back_callback = [ctx]()
{
application::state next_state;
next_state.name = "controls_menu";
next_state.enter = std::bind(game::state::controls_menu::enter, ctx);
next_state.exit = std::bind(game::state::controls_menu::exit, ctx);
ctx->app->change_state(next_state);
};
// Build list of menu select callbacks
ctx->menu_select_callbacks.push_back(select_back_callback);
// Build list of menu left callbacks
ctx->menu_left_callbacks.push_back(nullptr);
// Build list of menu right callbacks
ctx->menu_right_callbacks.push_back(nullptr);
// Set menu back callback
ctx->menu_back_callback = select_back_callback;
// Schedule menu control setup
timeline* timeline = ctx->timeline;
float t = timeline->get_position();
timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}});
}
void exit(game::context* ctx)
{
// Destruct menu
game::menu::clear_controls(ctx);
game::menu::clear_callbacks(ctx);
game::menu::remove_text_from_ui(ctx);
game::menu::delete_text(ctx);
ctx->ui_clear_pass->set_cleared_buffers(false, true, false);
} }
} // namespace controller_config_menu } // namespace controller_config_menu

+ 259
- 7
src/game/states/keyboard-config-menu.cpp View File

@ -24,30 +24,282 @@
#include "render/passes/clear-pass.hpp" #include "render/passes/clear-pass.hpp"
#include "debug/logger.hpp" #include "debug/logger.hpp"
#include "resources/resource-manager.hpp" #include "resources/resource-manager.hpp"
#include "game/menu.hpp"
#include "animation/timeline.hpp"
namespace game { namespace game {
namespace state { namespace state {
namespace keyboard_config_menu { namespace keyboard_config_menu {
void enter(game::context* ctx)
static std::string get_binding_string(game::context* ctx, input::control* control)
{ {
// Load control profile
if (ctx->config->contains("control_profile"))
std::string binding_string;
auto mappings = ctx->input_event_router->get_mappings(control);
for (input::mapping* mapping: *mappings)
{ {
json* profile = ctx->resource_manager->load<json>((*ctx->config)["control_profile"].get<std::string>());
std::string mapping_string;
for (auto& control_element: (*profile)["controls"].items())
switch (mapping->get_type())
{ {
ctx->logger->log(control_element.key());
case input::mapping_type::key:
{
const input::key_mapping* key_mapping = static_cast<const input::key_mapping*>(mapping);
const char* scancode_name = input::keyboard::get_scancode_name(key_mapping->scancode);
mapping_string = scancode_name;
break;
}
case input::mapping_type::mouse_wheel:
{
const input::mouse_wheel_mapping* wheel_mapping = static_cast<const input::mouse_wheel_mapping*>(mapping);
switch (wheel_mapping->axis)
{
case input::mouse_wheel_axis::negative_x:
mapping_string = (*ctx->strings)["mouse_wheel_left"];
break;
case input::mouse_wheel_axis::positive_x:
mapping_string = (*ctx->strings)["mouse_wheel_right"];
break;
case input::mouse_wheel_axis::negative_y:
mapping_string = (*ctx->strings)["mouse_wheel_down"];
break;
case input::mouse_wheel_axis::positive_y:
mapping_string = (*ctx->strings)["mouse_wheel_up"];
break;
default:
break;
}
break;
}
case input::mapping_type::mouse_button:
{
const input::mouse_button_mapping* button_mapping = static_cast<const input::mouse_button_mapping*>(mapping);
if (button_mapping->button == 1)
{
mapping_string = (*ctx->strings)["mouse_button_left"];
}
else if (button_mapping->button == 2)
{
mapping_string = (*ctx->strings)["mouse_button_middle"];
}
else if (button_mapping->button == 3)
{
mapping_string = (*ctx->strings)["mouse_button_right"];
}
else
{
const std::string& format = (*ctx->strings)["mouse_button_n"];
char buffer[64];
std::snprintf(buffer, 64, format.c_str(), button_mapping->button);
mapping_string = buffer;
}
break;
}
default:
break;
}
if (!mapping_string.empty())
{
if (binding_string.empty())
{
binding_string = mapping_string;
}
else
{
binding_string += " " + mapping_string;
}
} }
} }
return binding_string;
} }
void exit(game::context* ctx)
static void add_control_item(game::context* ctx, const std::string& control_name)
{ {
// Get pointer to control
input::control* control = ctx->controls[control_name];
// Construct texts
scene::text* name_text = new scene::text();
scene::text* value_text = new scene::text();
// Add texts to list of menu item texts
ctx->menu_item_texts.push_back({name_text, value_text});
// Set content of name text
std::string string_name = "control_" + control_name;
if (auto it = ctx->strings->find(string_name); it != ctx->strings->end())
name_text->set_content(it->second);
else
name_text->set_content(control_name);
// Set content of value text
value_text->set_content(get_binding_string(ctx, control));
auto select_callback = [ctx, control, value_text]()
{
// Clear binding string from value text
value_text->set_content((*ctx->strings)["ellipsis"]);
game::menu::align_text(ctx);
game::menu::update_text_tweens(ctx);
// Disable controls
game::menu::clear_controls(ctx);
// Remove keyboard and mouse event mappings from control
ctx->input_event_router->remove_mappings(control, input::mapping_type::key);
ctx->input_event_router->remove_mappings(control, input::mapping_type::mouse_motion);
ctx->input_event_router->remove_mappings(control, input::mapping_type::mouse_wheel);
ctx->input_event_router->remove_mappings(control, input::mapping_type::mouse_button);
// Setup input binding listener
ctx->input_listener->set_callback
(
[ctx, control, value_text](const event_base& event)
{
auto id = event.get_event_type_id();
if (id == key_pressed_event::event_type_id)
{
// Map key pressed event to control
const key_pressed_event& key_event = static_cast<const key_pressed_event&>(event);
ctx->input_event_router->add_mapping(input::key_mapping(control, key_event.keyboard, key_event.scancode));
}
else if (id == mouse_wheel_scrolled_event::event_type_id)
{
// Map mouse wheel scrolled event to control
const mouse_wheel_scrolled_event& wheel_event = static_cast<const mouse_wheel_scrolled_event&>(event);
input::mouse_wheel_axis axis;
if (wheel_event.x < 0)
axis = input::mouse_wheel_axis::negative_x;
else if (wheel_event.x > 0)
axis = input::mouse_wheel_axis::positive_x;
else if (wheel_event.y < 0)
axis = input::mouse_wheel_axis::negative_y;
else if (wheel_event.y > 0)
axis = input::mouse_wheel_axis::positive_y;
else
return;
ctx->input_event_router->add_mapping(input::mouse_wheel_mapping(control, wheel_event.mouse, axis));
}
else if (id == mouse_button_pressed_event::event_type_id)
{
// Map mouse button pressed event to control
const mouse_button_pressed_event& button_event = static_cast<const mouse_button_pressed_event&>(event);
ctx->input_event_router->add_mapping(input::mouse_button_mapping(control, button_event.mouse, button_event.button));
}
else
{
return;
}
// Update menu text
value_text->set_content(get_binding_string(ctx, control));
game::menu::align_text(ctx);
game::menu::update_text_tweens(ctx);
// Disable input listener
ctx->input_listener->set_enabled(false);
ctx->input_listener->set_callback(nullptr);
// Schedule re-enabling of menu controls
timeline* timeline = ctx->timeline;
float t = timeline->get_position();
timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}});
}
);
ctx->input_listener->set_enabled(true);
};
// Register menu item callbacks
ctx->menu_select_callbacks.push_back(select_callback);
ctx->menu_left_callbacks.push_back(nullptr);
ctx->menu_right_callbacks.push_back(nullptr);
}
void enter(game::context* ctx)
{
ctx->ui_clear_pass->set_cleared_buffers(true, true, false);
// Add camera control menu items
add_control_item(ctx, "dolly_forward");
add_control_item(ctx, "dolly_backward");
add_control_item(ctx, "truck_left");
add_control_item(ctx, "truck_right");
add_control_item(ctx, "pedestal_up");
add_control_item(ctx, "pedestal_down");
// Add application control menu items
add_control_item(ctx, "toggle_fullscreen");
add_control_item(ctx, "screenshot");
// Construct menu item texts
scene::text* back_text = new scene::text();
// Build list of menu item texts
ctx->menu_item_texts.push_back({back_text, nullptr});
// Set content of menu item texts
back_text->set_content((*ctx->strings)["back"]);
// Init menu item index
game::menu::init_menu_item_index(ctx, "keyboard_config");
game::menu::update_text_color(ctx);
game::menu::update_text_font(ctx);
game::menu::align_text(ctx);
game::menu::update_text_tweens(ctx);
game::menu::add_text_to_ui(ctx);
// Construct menu item callbacks
auto select_back_callback = [ctx]()
{
application::state next_state;
next_state.name = "controls_menu";
next_state.enter = std::bind(game::state::controls_menu::enter, ctx);
next_state.exit = std::bind(game::state::controls_menu::exit, ctx);
ctx->app->change_state(next_state);
};
// Build list of menu select callbacks
ctx->menu_select_callbacks.push_back(select_back_callback);
// Build list of menu left callbacks
ctx->menu_left_callbacks.push_back(nullptr);
// Build list of menu right callbacks
ctx->menu_right_callbacks.push_back(nullptr);
// Set menu back callback
ctx->menu_back_callback = select_back_callback;
// Schedule menu control setup
timeline* timeline = ctx->timeline;
float t = timeline->get_position();
timeline->add_sequence({{t + game::menu::input_delay, std::bind(game::menu::setup_controls, ctx)}});
}
void exit(game::context* ctx)
{
// Destruct menu
game::menu::clear_controls(ctx);
game::menu::clear_callbacks(ctx);
game::menu::remove_text_from_ui(ctx);
game::menu::delete_text(ctx);
ctx->ui_clear_pass->set_cleared_buffers(false, true, false);
} }
} // namespace keyboard_config_menu } // namespace keyboard_config_menu

+ 55
- 0
src/input/event-router.cpp View File

@ -144,6 +144,61 @@ void event_router::remove_mappings(control* control)
} }
} }
void event_router::remove_mappings(control* control, mapping_type type)
{
auto it = controls.find(control);
if (it != controls.end())
{
std::list<mapping*> flagged_mappings;
for (mapping* mapping: it->second)
{
if (mapping->get_type() != type)
continue;
// Flag mapping for deletion
flagged_mappings.push_back(mapping);
switch (mapping->get_type())
{
case mapping_type::key:
key_mappings.remove(static_cast<key_mapping*>(mapping));
break;
case mapping_type::mouse_motion:
mouse_motion_mappings.remove(static_cast<mouse_motion_mapping*>(mapping));
break;
case mapping_type::mouse_wheel:
mouse_wheel_mappings.remove(static_cast<mouse_wheel_mapping*>(mapping));
break;
case mapping_type::mouse_button:
mouse_button_mappings.remove(static_cast<mouse_button_mapping*>(mapping));
break;
case mapping_type::gamepad_axis:
gamepad_axis_mappings.remove(static_cast<gamepad_axis_mapping*>(mapping));
break;
case mapping_type::gamepad_button:
gamepad_button_mappings.remove(static_cast<gamepad_button_mapping*>(mapping));
break;
default:
break;
}
}
// Delete flagged mappings
for (mapping* mapping: flagged_mappings)
{
it->second.remove(mapping);
delete mapping;
}
}
}
void event_router::set_event_dispatcher(::event_dispatcher* event_dispatcher) void event_router::set_event_dispatcher(::event_dispatcher* event_dispatcher)
{ {
if (this->event_dispatcher) if (this->event_dispatcher)

+ 13
- 4
src/input/event-router.hpp View File

@ -29,6 +29,7 @@
namespace input { namespace input {
class control; class control;
enum class mapping_type;
class mapping; class mapping;
class key_mapping; class key_mapping;
class mouse_motion_mapping; class mouse_motion_mapping;
@ -75,19 +76,27 @@ public:
/** /**
* Removes all input mappings from the router that are associated with the specified control. * Removes all input mappings from the router that are associated with the specified control.
* *
* @param control control with which associated input mappings should be removed.
* @param control Control with which associated input mappings should be removed.
*/ */
void remove_mappings(control* control); void remove_mappings(control* control);
/** /**
* Sets the event dispatcher to which this input event router will subscribe itself.
* Removes all input mappings of a given type from the router that are associated with the specified control.
*
* @param control Control with which associated input mappings should be removed.
* @param type Type of input mapping to be removed.
*/ */
void set_event_dispatcher(event_dispatcher* event_dispatcher);
void remove_mappings(control* control, mapping_type type);
/** /**
* Removes all input mappings from the router. * Removes all input mappings from the router.
*/ */
void remove_mappings(); void remove_mappings();
/**
* Sets the event dispatcher to which this input event router will subscribe itself.
*/
void set_event_dispatcher(event_dispatcher* event_dispatcher);
/// Returns a list of mappings for the specified control, or nullptr if the control is unmapped. /// Returns a list of mappings for the specified control, or nullptr if the control is unmapped.
const std::list<mapping*>* get_mappings(control* control) const; const std::list<mapping*>* get_mappings(control* control) const;

+ 35
- 55
src/input/listener.cpp View File

@ -19,6 +19,7 @@
#include "listener.hpp" #include "listener.hpp"
#include "event/event-dispatcher.hpp" #include "event/event-dispatcher.hpp"
#include <iostream>
namespace input { namespace input {
@ -35,26 +36,29 @@ listener::~listener()
void listener::set_event_dispatcher(::event_dispatcher* event_dispatcher) void listener::set_event_dispatcher(::event_dispatcher* event_dispatcher)
{ {
if (this->event_dispatcher)
if (event_dispatcher != this->event_dispatcher)
{ {
this->event_dispatcher->unsubscribe<key_pressed_event>(this);
this->event_dispatcher->unsubscribe<mouse_moved_event>(this);
this->event_dispatcher->unsubscribe<mouse_wheel_scrolled_event>(this);
this->event_dispatcher->unsubscribe<mouse_button_pressed_event>(this);
this->event_dispatcher->unsubscribe<gamepad_axis_moved_event>(this);
this->event_dispatcher->unsubscribe<gamepad_button_pressed_event>(this);
}
this->event_dispatcher = event_dispatcher;
if (event_dispatcher)
{
event_dispatcher->subscribe<key_pressed_event>(this);
event_dispatcher->subscribe<mouse_moved_event>(this);
event_dispatcher->subscribe<mouse_wheel_scrolled_event>(this);
event_dispatcher->subscribe<mouse_button_pressed_event>(this);
event_dispatcher->subscribe<gamepad_axis_moved_event>(this);
event_dispatcher->subscribe<gamepad_button_pressed_event>(this);
if (this->event_dispatcher)
{
this->event_dispatcher->unsubscribe<key_pressed_event>(this);
this->event_dispatcher->unsubscribe<mouse_moved_event>(this);
this->event_dispatcher->unsubscribe<mouse_wheel_scrolled_event>(this);
this->event_dispatcher->unsubscribe<mouse_button_pressed_event>(this);
this->event_dispatcher->unsubscribe<gamepad_axis_moved_event>(this);
this->event_dispatcher->unsubscribe<gamepad_button_pressed_event>(this);
}
if (event_dispatcher)
{
event_dispatcher->subscribe<key_pressed_event>(this);
event_dispatcher->subscribe<mouse_moved_event>(this);
event_dispatcher->subscribe<mouse_wheel_scrolled_event>(this);
event_dispatcher->subscribe<mouse_button_pressed_event>(this);
event_dispatcher->subscribe<gamepad_axis_moved_event>(this);
event_dispatcher->subscribe<gamepad_button_pressed_event>(this);
}
this->event_dispatcher = event_dispatcher;
} }
} }
@ -70,62 +74,38 @@ void listener::set_enabled(bool enabled)
void listener::handle_event(const key_pressed_event& event) void listener::handle_event(const key_pressed_event& event)
{ {
if (!is_enabled() || !callback)
{
return;
}
callback(event);
if (enabled && callback)
callback(event);
} }
void listener::handle_event(const mouse_moved_event& event) void listener::handle_event(const mouse_moved_event& event)
{ {
if (!is_enabled() || !callback)
{
return;
}
callback(event);
if (enabled && callback)
callback(event);
} }
void listener::handle_event(const mouse_button_pressed_event& event) void listener::handle_event(const mouse_button_pressed_event& event)
{ {
if (!is_enabled() || !callback)
{
return;
}
callback(event);
if (enabled && callback)
callback(event);
} }
void listener::handle_event(const mouse_wheel_scrolled_event& event) void listener::handle_event(const mouse_wheel_scrolled_event& event)
{ {
if (!is_enabled() || !callback)
{
return;
}
callback(event);
if (enabled && callback)
callback(event);
} }
void listener::handle_event(const gamepad_button_pressed_event& event) void listener::handle_event(const gamepad_button_pressed_event& event)
{ {
if (!is_enabled() || !callback)
{
return;
}
callback(event);
if (enabled && callback)
callback(event);
} }
void listener::handle_event(const gamepad_axis_moved_event& event) void listener::handle_event(const gamepad_axis_moved_event& event)
{ {
if (!is_enabled() || !callback)
{
return;
}
callback(event);
if (enabled && callback)
callback(event);
} }
} // namespace input } // namespace input

Loading…
Cancel
Save