mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-04 14:01:25 +12:00
[overlays] Implement input suspend+resume
- Tested with OSK + home menu. Requires hacks to enable this setup so it's mostly an academic achievement.
This commit is contained in:
parent
b27366e1e6
commit
6d4967ffef
4 changed files with 58 additions and 19 deletions
|
@ -158,13 +158,18 @@ namespace rsx
|
||||||
{
|
{
|
||||||
if (auto iface = std::dynamic_pointer_cast<user_interface>(get(uid)))
|
if (auto iface = std::dynamic_pointer_cast<user_interface>(get(uid)))
|
||||||
{
|
{
|
||||||
// TODO: Hijack input immediately!
|
std::lock_guard lock(m_input_stack_guard);
|
||||||
|
|
||||||
|
// Add our interface to the queue
|
||||||
m_input_token_stack.push(
|
m_input_token_stack.push(
|
||||||
name,
|
name,
|
||||||
std::move(iface),
|
std::move(iface),
|
||||||
on_input_loop_enter,
|
on_input_loop_enter,
|
||||||
on_input_loop_exit,
|
on_input_loop_exit,
|
||||||
input_loop_override);
|
input_loop_override);
|
||||||
|
|
||||||
|
// Signal input thread loop after pushing to avoid a race.
|
||||||
|
m_input_thread_interrupted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,10 +189,12 @@ namespace rsx
|
||||||
{
|
{
|
||||||
// Avoid tail recursion by reinserting pushed-down items
|
// Avoid tail recursion by reinserting pushed-down items
|
||||||
std::vector<input_thread_context_t> interrupted_items;
|
std::vector<input_thread_context_t> interrupted_items;
|
||||||
bool in_interrupted_mode = false;
|
|
||||||
|
|
||||||
while (!m_input_thread_abort)
|
while (!m_input_thread_abort)
|
||||||
{
|
{
|
||||||
|
// We're about to load the whole list, interruption makes no sense before this point
|
||||||
|
m_input_thread_interrupted = false;
|
||||||
|
|
||||||
for (auto&& input_context : m_input_token_stack.pop_all_reversed())
|
for (auto&& input_context : m_input_token_stack.pop_all_reversed())
|
||||||
{
|
{
|
||||||
if (input_context.target->is_detached())
|
if (input_context.target->is_detached())
|
||||||
|
@ -195,10 +202,18 @@ namespace rsx
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_interrupted_mode)
|
if (m_input_thread_interrupted)
|
||||||
{
|
{
|
||||||
interrupted_items.push_back(input_context);
|
// Someone just pushed something onto the stack. Check if we already saw it.
|
||||||
continue;
|
if (m_input_token_stack)
|
||||||
|
{
|
||||||
|
// We actually have new items to read out. Skip the remaining list.
|
||||||
|
interrupted_items.push_back(input_context);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// False alarm, we already saw it.
|
||||||
|
m_input_thread_interrupted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input_context.input_loop_prologue &&
|
if (input_context.input_loop_prologue &&
|
||||||
|
@ -209,9 +224,14 @@ namespace rsx
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 result = 0;
|
s32 result = 0;
|
||||||
|
|
||||||
if (!input_context.input_loop_override) [[ likely ]]
|
if (!input_context.input_loop_override) [[ likely ]]
|
||||||
{
|
{
|
||||||
result = input_context.target->run_input_loop();
|
result = input_context.target->run_input_loop([this]()
|
||||||
|
{
|
||||||
|
// Stop if interrupt status is set or input stack is empty
|
||||||
|
return !m_input_thread_interrupted || !m_input_token_stack;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -220,8 +240,9 @@ namespace rsx
|
||||||
|
|
||||||
if (result == user_interface::selection_code::interrupted)
|
if (result == user_interface::selection_code::interrupted)
|
||||||
{
|
{
|
||||||
// Push back the items onto the stack
|
// This dialog was exited prematurely, so we must re-run it's input routine later.
|
||||||
in_interrupted_mode = true;
|
ensure(m_input_thread_interrupted);
|
||||||
|
ensure(m_input_token_stack);
|
||||||
interrupted_items.push_back(input_context);
|
interrupted_items.push_back(input_context);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -236,12 +257,27 @@ namespace rsx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_interrupted_mode)
|
if (!interrupted_items.empty())
|
||||||
{
|
{
|
||||||
for (const auto& iface : interrupted_items)
|
std::lock_guard lock(m_input_stack_guard);
|
||||||
|
|
||||||
|
// We need to rebuild the stack in reverse order here
|
||||||
|
const auto current_stack = m_input_token_stack.pop_all();
|
||||||
|
|
||||||
|
// Re-insert interrupted list
|
||||||
|
for (auto it = interrupted_items.crbegin(); it != interrupted_items.crend(); ++it)
|
||||||
|
{
|
||||||
|
m_input_token_stack.push(*it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-insert the 'new' list oldest-first
|
||||||
|
for (const auto& iface : current_stack)
|
||||||
{
|
{
|
||||||
m_input_token_stack.push(iface);
|
m_input_token_stack.push(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
interrupted_items.clear();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -181,6 +181,8 @@ namespace rsx
|
||||||
|
|
||||||
lf_queue<input_thread_context_t> m_input_token_stack;
|
lf_queue<input_thread_context_t> m_input_token_stack;
|
||||||
atomic_t<bool> m_input_thread_abort = false;
|
atomic_t<bool> m_input_thread_abort = false;
|
||||||
|
atomic_t<bool> m_input_thread_interrupted = false;
|
||||||
|
shared_mutex m_input_stack_guard;
|
||||||
|
|
||||||
std::shared_ptr<named_thread<overlay_input_thread>> m_input_thread;
|
std::shared_ptr<named_thread<overlay_input_thread>> m_input_thread;
|
||||||
void input_thread_loop();
|
void input_thread_loop();
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace rsx
|
||||||
// Singleton instance declaration
|
// Singleton instance declaration
|
||||||
fontmgr* fontmgr::m_instance = nullptr;
|
fontmgr* fontmgr::m_instance = nullptr;
|
||||||
|
|
||||||
s32 user_interface::run_input_loop()
|
s32 user_interface::run_input_loop(std::function<bool()> check_state)
|
||||||
{
|
{
|
||||||
user_interface::thread_bits_allocator thread_bits_alloc(this);
|
user_interface::thread_bits_allocator thread_bits_alloc(this);
|
||||||
|
|
||||||
|
@ -122,8 +122,14 @@ namespace rsx
|
||||||
last_button_state[pad_index][button_id] = pressed;
|
last_button_state[pad_index][button_id] = pressed;
|
||||||
};
|
};
|
||||||
|
|
||||||
while (!m_stop_input_loop && !m_input_loop_interrupted)
|
while (!m_stop_input_loop)
|
||||||
{
|
{
|
||||||
|
if (check_state && !check_state())
|
||||||
|
{
|
||||||
|
// Interrupted externally.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (Emu.IsStopped())
|
if (Emu.IsStopped())
|
||||||
{
|
{
|
||||||
return selection_code::canceled;
|
return selection_code::canceled;
|
||||||
|
@ -361,9 +367,7 @@ namespace rsx
|
||||||
input::SetIntercepted(false);
|
input::SetIntercepted(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_interactive = false;
|
return !m_stop_input_loop
|
||||||
|
|
||||||
return (m_input_loop_interrupted && !m_stop_input_loop)
|
|
||||||
? selection_code::interrupted
|
? selection_code::interrupted
|
||||||
: selection_code::ok;
|
: selection_code::ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,6 @@ namespace rsx
|
||||||
bool m_start_pad_interception = true;
|
bool m_start_pad_interception = true;
|
||||||
atomic_t<bool> m_stop_pad_interception = false;
|
atomic_t<bool> m_stop_pad_interception = false;
|
||||||
atomic_t<bool> m_input_thread_detached = false;
|
atomic_t<bool> m_input_thread_detached = false;
|
||||||
atomic_t<bool> m_input_loop_interrupted = false;
|
|
||||||
atomic_t<u64> thread_bits = 0;
|
atomic_t<u64> thread_bits = 0;
|
||||||
bool m_keyboard_input_enabled = false; // Allow keyboard input
|
bool m_keyboard_input_enabled = false; // Allow keyboard input
|
||||||
bool m_keyboard_pad_handler_active = true; // Initialized as true to prevent keyboard input until proven otherwise.
|
bool m_keyboard_pad_handler_active = true; // Initialized as true to prevent keyboard input until proven otherwise.
|
||||||
|
@ -152,8 +151,6 @@ namespace rsx
|
||||||
|
|
||||||
bool is_detached() const { return m_input_thread_detached; }
|
bool is_detached() const { return m_input_thread_detached; }
|
||||||
void detach_input() { m_input_thread_detached.store(true); }
|
void detach_input() { m_input_thread_detached.store(true); }
|
||||||
void on_input_interrupted() { m_input_loop_interrupted.store(true); }
|
|
||||||
void on_input_resumed() { m_input_loop_interrupted.store(false); }
|
|
||||||
|
|
||||||
void update() override {}
|
void update() override {}
|
||||||
|
|
||||||
|
@ -164,7 +161,7 @@ namespace rsx
|
||||||
|
|
||||||
virtual void close(bool use_callback, bool stop_pad_interception);
|
virtual void close(bool use_callback, bool stop_pad_interception);
|
||||||
|
|
||||||
s32 run_input_loop();
|
s32 run_input_loop(std::function<bool()> check_state = nullptr);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue