mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp.git
synced 2026-04-27 12:41:39 +00:00
Implement controlling input capturing for mod UI contexts
This commit is contained in:
parent
7261c055a1
commit
2dffaf6148
6 changed files with 121 additions and 21 deletions
|
|
@ -49,7 +49,8 @@ namespace recompui {
|
||||||
void hide_context(ContextId context);
|
void hide_context(ContextId context);
|
||||||
void hide_all_contexts();
|
void hide_all_contexts();
|
||||||
bool is_context_shown(ContextId context);
|
bool is_context_shown(ContextId context);
|
||||||
bool is_context_taking_input();
|
bool is_context_capturing_input();
|
||||||
|
bool is_context_capturing_mouse();
|
||||||
bool is_any_context_shown();
|
bool is_any_context_shown();
|
||||||
|
|
||||||
ContextId get_launcher_context_id();
|
ContextId get_launcher_context_id();
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) {
|
||||||
SDL_KeyboardEvent* keyevent = &event->key;
|
SDL_KeyboardEvent* keyevent = &event->key;
|
||||||
|
|
||||||
// Skip repeated events when not in the menu
|
// Skip repeated events when not in the menu
|
||||||
if (!recompui::is_context_taking_input() &&
|
if (!recompui::is_context_capturing_input() &&
|
||||||
event->key.repeat) {
|
event->key.repeat) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -713,7 +713,7 @@ void recomp::set_right_analog_suppressed(bool suppressed) {
|
||||||
|
|
||||||
bool recomp::game_input_disabled() {
|
bool recomp::game_input_disabled() {
|
||||||
// Disable input if any menu that blocks input is open.
|
// Disable input if any menu that blocks input is open.
|
||||||
return recompui::is_context_taking_input();
|
return recompui::is_context_capturing_input();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool recomp::all_input_disabled() {
|
bool recomp::all_input_disabled() {
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ namespace recompui {
|
||||||
Element root_element;
|
Element root_element;
|
||||||
std::vector<Element*> loose_elements;
|
std::vector<Element*> loose_elements;
|
||||||
std::unordered_set<ResourceId> to_update;
|
std::unordered_set<ResourceId> to_update;
|
||||||
|
bool captures_input = true;
|
||||||
|
bool captures_mouse = true;
|
||||||
Context(Rml::ElementDocument* document) : document(document), root_element(document) {}
|
Context(Rml::ElementDocument* document) : document(document), root_element(document) {}
|
||||||
};
|
};
|
||||||
} // namespace recompui
|
} // namespace recompui
|
||||||
|
|
@ -371,6 +373,47 @@ void recompui::ContextId::process_updates() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool recompui::ContextId::captures_input() {
|
||||||
|
std::lock_guard lock{ context_state.all_contexts_lock };
|
||||||
|
|
||||||
|
Context* ctx = context_state.all_contexts.get(context_slotmap::key{ slot_id });
|
||||||
|
if (ctx == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ctx->captures_input;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recompui::ContextId::captures_mouse() {
|
||||||
|
std::lock_guard lock{ context_state.all_contexts_lock };
|
||||||
|
|
||||||
|
Context* ctx = context_state.all_contexts.get(context_slotmap::key{ slot_id });
|
||||||
|
if (ctx == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ctx->captures_mouse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recompui::ContextId::set_captures_input(bool captures_input) {
|
||||||
|
std::lock_guard lock{ context_state.all_contexts_lock };
|
||||||
|
|
||||||
|
Context* ctx = context_state.all_contexts.get(context_slotmap::key{ slot_id });
|
||||||
|
if (ctx == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx->captures_input = captures_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recompui::ContextId::set_captures_mouse(bool captures_mouse) {
|
||||||
|
std::lock_guard lock{ context_state.all_contexts_lock };
|
||||||
|
|
||||||
|
Context* ctx = context_state.all_contexts.get(context_slotmap::key{ slot_id });
|
||||||
|
if (ctx == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx->captures_mouse = captures_mouse;
|
||||||
|
}
|
||||||
|
|
||||||
recompui::Style* recompui::ContextId::add_resource_impl(std::unique_ptr<Style>&& resource) {
|
recompui::Style* recompui::ContextId::add_resource_impl(std::unique_ptr<Style>&& resource) {
|
||||||
// Ensure a context is currently opened by this thread.
|
// Ensure a context is currently opened by this thread.
|
||||||
if (opened_context_id == ContextId::null()) {
|
if (opened_context_id == ContextId::null()) {
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,11 @@ namespace recompui {
|
||||||
|
|
||||||
static constexpr ContextId null() { return ContextId{ .slot_id = uint32_t(-1) }; }
|
static constexpr ContextId null() { return ContextId{ .slot_id = uint32_t(-1) }; }
|
||||||
|
|
||||||
// TODO
|
bool captures_input();
|
||||||
bool takes_input() { return true; }
|
bool captures_mouse();
|
||||||
|
|
||||||
|
void set_captures_input(bool captures_input);
|
||||||
|
void set_captures_mouse(bool captures_input);
|
||||||
};
|
};
|
||||||
|
|
||||||
ContextId create_context(const std::filesystem::path& path);
|
ContextId create_context(const std::filesystem::path& path);
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,20 @@ void recompui_hide_context(uint8_t* rdram, recomp_context* ctx) {
|
||||||
recompui::hide_context(ui_context);
|
recompui::hide_context(ui_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void recompui_set_context_captures_input(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
ContextId ui_context = get_context(rdram, ctx);
|
||||||
|
bool captures_input = _arg<1, int>(rdram, ctx) != 0;
|
||||||
|
|
||||||
|
ui_context.set_captures_input(captures_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void recompui_set_context_captures_mouse(uint8_t* rdram, recomp_context* ctx) {
|
||||||
|
ContextId ui_context = get_context(rdram, ctx);
|
||||||
|
bool captures_mouse = _arg<1, int>(rdram, ctx) != 0;
|
||||||
|
|
||||||
|
ui_context.set_captures_mouse(captures_mouse);
|
||||||
|
}
|
||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
void recompui_create_style(uint8_t* rdram, recomp_context* ctx) {
|
void recompui_create_style(uint8_t* rdram, recomp_context* ctx) {
|
||||||
ContextId ui_context = get_context(rdram, ctx);
|
ContextId ui_context = get_context(rdram, ctx);
|
||||||
|
|
@ -780,6 +794,8 @@ void recompui::register_ui_exports() {
|
||||||
REGISTER_FUNC(recompui_context_root);
|
REGISTER_FUNC(recompui_context_root);
|
||||||
REGISTER_FUNC(recompui_show_context);
|
REGISTER_FUNC(recompui_show_context);
|
||||||
REGISTER_FUNC(recompui_hide_context);
|
REGISTER_FUNC(recompui_hide_context);
|
||||||
|
REGISTER_FUNC(recompui_set_context_captures_input);
|
||||||
|
REGISTER_FUNC(recompui_set_context_captures_mouse);
|
||||||
REGISTER_FUNC(recompui_create_style);
|
REGISTER_FUNC(recompui_create_style);
|
||||||
REGISTER_FUNC(recompui_create_element);
|
REGISTER_FUNC(recompui_create_element);
|
||||||
REGISTER_FUNC(recompui_create_label);
|
REGISTER_FUNC(recompui_create_label);
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,6 @@ Rml::Element* find_autofocus_element(Rml::Element* start) {
|
||||||
struct ContextDetails {
|
struct ContextDetails {
|
||||||
recompui::ContextId context;
|
recompui::ContextId context;
|
||||||
Rml::ElementDocument* document;
|
Rml::ElementDocument* document;
|
||||||
bool takes_input;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class UIState {
|
class UIState {
|
||||||
|
|
@ -266,7 +265,7 @@ public:
|
||||||
recompui::set_cursor_visible(mouse_is_active);
|
recompui::set_cursor_visible(mouse_is_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rml::ElementDocument* current_document = top_input_document();
|
Rml::ElementDocument* current_document = top_mouse_document();
|
||||||
if (current_document == nullptr) {
|
if (current_document == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -286,7 +285,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_focus(bool mouse_moved, bool non_mouse_interacted) {
|
void update_focus(bool mouse_moved, bool non_mouse_interacted) {
|
||||||
Rml::ElementDocument* current_document = top_input_document();
|
Rml::ElementDocument* current_document = top_mouse_document();
|
||||||
|
|
||||||
if (current_document == nullptr) {
|
if (current_document == nullptr) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -341,12 +340,10 @@ public:
|
||||||
recompui::message_box("Attemped to show the same context twice");
|
recompui::message_box("Attemped to show the same context twice");
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
bool takes_input = context.takes_input();
|
|
||||||
Rml::ElementDocument* document = context.get_document();
|
Rml::ElementDocument* document = context.get_document();
|
||||||
shown_contexts.push_back(ContextDetails{
|
shown_contexts.push_back(ContextDetails{
|
||||||
.context = context,
|
.context = context,
|
||||||
.document = document,
|
.document = document
|
||||||
.takes_input = takes_input
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// auto& on_show = context.on_show;
|
// auto& on_show = context.on_show;
|
||||||
|
|
@ -383,8 +380,12 @@ public:
|
||||||
return std::find_if(shown_contexts.begin(), shown_contexts.end(), [context](auto& c){ return c.context == context; }) != shown_contexts.end();
|
return std::find_if(shown_contexts.begin(), shown_contexts.end(), [context](auto& c){ return c.context == context; }) != shown_contexts.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_context_taking_input() {
|
bool is_context_capturing_input() {
|
||||||
return std::find_if(shown_contexts.begin(), shown_contexts.end(), [](auto& c){ return c.takes_input; }) != shown_contexts.end();
|
return std::find_if(shown_contexts.begin(), shown_contexts.end(), [](auto& c){ return c.context.captures_input(); }) != shown_contexts.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_context_capturing_mouse() {
|
||||||
|
return std::find_if(shown_contexts.begin(), shown_contexts.end(), [](auto& c){ return c.context.captures_mouse(); }) != shown_contexts.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_any_context_shown() {
|
bool is_any_context_shown() {
|
||||||
|
|
@ -394,7 +395,17 @@ public:
|
||||||
Rml::ElementDocument* top_input_document() {
|
Rml::ElementDocument* top_input_document() {
|
||||||
// Iterate backwards and stop at the first context that takes input.
|
// Iterate backwards and stop at the first context that takes input.
|
||||||
for (auto it = shown_contexts.rbegin(); it != shown_contexts.rend(); it++) {
|
for (auto it = shown_contexts.rbegin(); it != shown_contexts.rend(); it++) {
|
||||||
if (it->takes_input) {
|
if (it->context.captures_input()) {
|
||||||
|
return it->document;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::ElementDocument* top_mouse_document() {
|
||||||
|
// Iterate backwards and stop at the first context that takes input.
|
||||||
|
for (auto it = shown_contexts.rbegin(); it != shown_contexts.rend(); it++) {
|
||||||
|
if (it->context.captures_mouse()) {
|
||||||
return it->document;
|
return it->document;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -556,8 +567,10 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
||||||
bool config_was_open = recompui::is_context_shown(recompui::get_config_context_id()) || recompui::is_context_shown(recompui::get_config_sub_menu_context_id());
|
bool config_was_open = recompui::is_context_shown(recompui::get_config_context_id()) || recompui::is_context_shown(recompui::get_config_sub_menu_context_id());
|
||||||
|
|
||||||
while (recompui::try_deque_event(cur_event)) {
|
while (recompui::try_deque_event(cur_event)) {
|
||||||
bool context_taking_input = recompui::is_context_taking_input();
|
bool context_capturing_input = recompui::is_context_capturing_input();
|
||||||
|
bool context_capturing_mouse = recompui::is_context_capturing_mouse();
|
||||||
if (!recomp::all_input_disabled()) {
|
if (!recomp::all_input_disabled()) {
|
||||||
|
bool is_mouse_input = false;
|
||||||
// Implement some additional behavior for specific events on top of what RmlUi normally does with them.
|
// Implement some additional behavior for specific events on top of what RmlUi normally does with them.
|
||||||
switch (cur_event.type) {
|
switch (cur_event.type) {
|
||||||
case SDL_EventType::SDL_MOUSEMOTION: {
|
case SDL_EventType::SDL_MOUSEMOTION: {
|
||||||
|
|
@ -582,11 +595,17 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
||||||
case SDL_EventType::SDL_MOUSEBUTTONDOWN:
|
case SDL_EventType::SDL_MOUSEBUTTONDOWN:
|
||||||
mouse_moved = true;
|
mouse_moved = true;
|
||||||
mouse_clicked = true;
|
mouse_clicked = true;
|
||||||
|
is_mouse_input = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_EventType::SDL_MOUSEBUTTONUP:
|
||||||
|
case SDL_EventType::SDL_MOUSEWHEEL:
|
||||||
|
is_mouse_input = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EventType::SDL_CONTROLLERBUTTONDOWN: {
|
case SDL_EventType::SDL_CONTROLLERBUTTONDOWN: {
|
||||||
int rml_key = cont_button_to_key(cur_event.cbutton);
|
int rml_key = cont_button_to_key(cur_event.cbutton);
|
||||||
if (context_taking_input && rml_key) {
|
if (context_capturing_input && rml_key) {
|
||||||
ui_state->context->ProcessKeyDown(RmlSDL::ConvertKey(rml_key), 0);
|
ui_state->context->ProcessKeyDown(RmlSDL::ConvertKey(rml_key), 0);
|
||||||
}
|
}
|
||||||
non_mouse_interacted = true;
|
non_mouse_interacted = true;
|
||||||
|
|
@ -619,7 +638,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
||||||
*await_stick_return = true;
|
*await_stick_return = true;
|
||||||
non_mouse_interacted = true;
|
non_mouse_interacted = true;
|
||||||
int rml_key = cont_axis_to_key(cur_event.caxis, axis_value);
|
int rml_key = cont_axis_to_key(cur_event.caxis, axis_value);
|
||||||
if (context_taking_input && rml_key) {
|
if (context_capturing_input && rml_key) {
|
||||||
ui_state->context->ProcessKeyDown(RmlSDL::ConvertKey(rml_key), 0);
|
ui_state->context->ProcessKeyDown(RmlSDL::ConvertKey(rml_key), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -632,8 +651,16 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context_taking_input) {
|
// Send the event to RmlUi if this type of event is being captured.
|
||||||
RmlSDL::InputEventHandler(ui_state->context, cur_event);
|
if (is_mouse_input) {
|
||||||
|
if (context_capturing_mouse) {
|
||||||
|
RmlSDL::InputEventHandler(ui_state->context, cur_event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (context_capturing_input) {
|
||||||
|
RmlSDL::InputEventHandler(ui_state->context, cur_event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -753,14 +780,24 @@ bool recompui::is_context_shown(ContextId context) {
|
||||||
return ui_state->is_context_shown(context);
|
return ui_state->is_context_shown(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool recompui::is_context_taking_input() {
|
bool recompui::is_context_capturing_input() {
|
||||||
std::lock_guard lock{ui_state_mutex};
|
std::lock_guard lock{ui_state_mutex};
|
||||||
|
|
||||||
if (!ui_state) {
|
if (!ui_state) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ui_state->is_context_taking_input();
|
return ui_state->is_context_capturing_input();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recompui::is_context_capturing_mouse() {
|
||||||
|
std::lock_guard lock{ui_state_mutex};
|
||||||
|
|
||||||
|
if (!ui_state) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ui_state->is_context_capturing_mouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool recompui::is_any_context_shown() {
|
bool recompui::is_any_context_shown() {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue