GunCon: Add relative pointer binding

This commit is contained in:
Stenzek
2023-09-20 16:56:12 +10:00
parent e63b2eec38
commit 7e07d2feb8
21 changed files with 779 additions and 507 deletions

View File

@ -71,6 +71,8 @@ static std::vector<u8> s_standard_font_data;
static std::vector<u8> s_fixed_font_data;
static std::vector<u8> s_icon_font_data;
static float s_window_width;
static float s_window_height;
static Common::Timer s_last_render_time;
// cached copies of WantCaptureKeyboard/Mouse, used to know when to dispatch events
@ -160,9 +162,10 @@ bool ImGuiManager::Initialize(float global_scale, bool show_osd_messages)
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
#endif
s_window_width = static_cast<float>(g_gpu_device->GetWindowWidth());
s_window_height = static_cast<float>(g_gpu_device->GetWindowHeight());
io.DisplayFramebufferScale = ImVec2(1, 1); // We already scale things ourselves, this would double-apply scaling
io.DisplaySize.x = static_cast<float>(g_gpu_device->GetWindowWidth());
io.DisplaySize.y = static_cast<float>(g_gpu_device->GetWindowHeight());
io.DisplaySize = ImVec2(s_window_width, s_window_height);
SetKeyMap();
SetStyle();
@ -197,12 +200,24 @@ void ImGuiManager::Shutdown()
ImGuiFullscreen::SetFonts(nullptr, nullptr, nullptr);
}
float ImGuiManager::GetWindowWidth()
{
return s_window_width;
}
float ImGuiManager::GetWindowHeight()
{
return s_window_height;
}
void ImGuiManager::WindowResized()
{
const u32 new_width = g_gpu_device ? g_gpu_device->GetWindowWidth() : 0;
const u32 new_height = g_gpu_device ? g_gpu_device->GetWindowHeight() : 0;
ImGui::GetIO().DisplaySize = ImVec2(static_cast<float>(new_width), static_cast<float>(new_height));
s_window_width = static_cast<float>(new_width);
s_window_height = static_cast<float>(new_height);
ImGui::GetIO().DisplaySize = ImVec2(s_window_width, s_window_height);
// restart imgui frame on the new window size to pick it up, otherwise we draw to the old size
ImGui::EndFrame();
@ -727,7 +742,7 @@ void ImGuiManager::DrawOSDMessages(Common::Timer::Value current_time)
const float margin = std::ceil(10.0f * scale);
const float padding = std::ceil(8.0f * scale);
const float rounding = std::ceil(5.0f * scale);
const float max_width = ImGui::GetIO().DisplaySize.x - (margin + padding) * 2.0f;
const float max_width = s_window_width - (margin + padding) * 2.0f;
float position_x = margin;
float position_y = margin;
@ -938,7 +953,7 @@ bool ImGuiManager::ProcessGenericInputEvent(GenericInputBinding key, float value
void ImGuiManager::CreateSoftwareCursorTextures()
{
for (u32 i = 0; i < InputManager::MAX_POINTER_DEVICES; i++)
for (u32 i = 0; i < static_cast<u32>(s_software_cursors.size()); i++)
{
if (!s_software_cursors[i].image_path.empty())
UpdateSoftwareCursorTexture(i);
@ -947,10 +962,8 @@ void ImGuiManager::CreateSoftwareCursorTextures()
void ImGuiManager::DestroySoftwareCursorTextures()
{
for (u32 i = 0; i < InputManager::MAX_POINTER_DEVICES; i++)
{
s_software_cursors[i].texture.reset();
}
for (SoftwareCursor& sc : s_software_cursors)
sc.texture.reset();
}
void ImGuiManager::UpdateSoftwareCursorTexture(u32 index)

View File

@ -30,6 +30,10 @@ bool Initialize(float global_scale, bool show_osd_messages);
/// Frees all ImGui resources.
void Shutdown();
/// Returns the size of the display window. Can be safely called from any thread.
float GetWindowWidth();
float GetWindowHeight();
/// Updates internal state when the window is size.
void WindowResized();

View File

@ -174,6 +174,9 @@ static std::array<std::array<PointerAxisState, static_cast<u8>(InputPointerAxis:
s_pointer_state;
static std::array<float, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_scale;
using PointerMoveCallback = std::function<void(InputBindingKey key, float value)>;
static std::vector<std::pair<u32, PointerMoveCallback>> s_pointer_move_callbacks;
// ------------------------------------------------------------------------
// Binding Parsing
// ------------------------------------------------------------------------
@ -699,16 +702,60 @@ void InputManager::AddPadBindings(SettingsInterface& si, const std::string& sect
{
const Controller::ControllerBindingInfo& bi = cinfo->bindings[i];
const std::vector<std::string> bindings(si.GetStringList(section.c_str(), bi.name));
if (!bindings.empty())
{
AddBindings(bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index](float value) {
if (!System::IsValid())
return;
Controller* c = System::GetController(pad_index);
if (c)
c->SetBindState(bind_index, value);
}});
switch (bi.type)
{
case InputBindingInfo::Type::Button:
case InputBindingInfo::Type::HalfAxis:
case InputBindingInfo::Type::Axis:
{
if (!bindings.empty())
{
AddBindings(bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index](float value) {
if (!System::IsValid())
return;
Controller* c = System::GetController(pad_index);
if (c)
c->SetBindState(bind_index, value);
}});
}
}
break;
case InputBindingInfo::Type::Pointer:
{
auto cb = [pad_index, base = bi.bind_index](InputBindingKey key, float value) {
if (!System::IsValid())
return;
Controller* c = System::GetController(pad_index);
if (c)
c->SetBindState(base + key.data, value);
};
// bind pointer 0 by default
if (bindings.empty())
{
s_pointer_move_callbacks.emplace_back(0, std::move(cb));
}
else
{
for (const std::string& binding : bindings)
{
const std::optional<u32> key(GetIndexFromPointerBinding(binding));
if (!key.has_value())
continue;
s_pointer_move_callbacks.emplace_back(0, cb);
}
}
}
break;
default:
Log_ErrorPrintf("Unhandled binding info type %u", static_cast<u32>(bi.type));
break;
}
}
@ -996,6 +1043,8 @@ bool InputManager::PreprocessEvent(InputBindingKey key, float value, GenericInpu
void InputManager::GenerateRelativeMouseEvents()
{
const bool system_running = System::IsRunning();
for (u32 device = 0; device < MAX_POINTER_DEVICES; device++)
{
for (u32 axis = 0; axis < static_cast<u32>(static_cast<u8>(InputPointerAxis::Count)); axis++)
@ -1011,12 +1060,24 @@ void InputManager::GenerateRelativeMouseEvents()
continue;
}
if (!system_running)
continue;
const float value = std::clamp(unclamped_value, -1.0f, 1.0f);
if (value != state.last_value)
{
state.last_value = value;
InvokeEvents(key, value, GenericInputBinding::Unknown);
}
if (delta != 0.0f)
{
for (const std::pair<u32, PointerMoveCallback>& pmc : s_pointer_move_callbacks)
{
if (pmc.first == device)
pmc.second(key, delta);
}
}
}
}
}
@ -1062,7 +1123,24 @@ void InputManager::UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis,
void InputManager::UpdateHostMouseMode()
{
// TODO: Move from System to here.
// Check for relative mode bindings, and enable if there's anything using it.
bool has_relative_mode_bindings = !s_pointer_move_callbacks.empty();
if (!has_relative_mode_bindings)
{
for (const auto& it : s_binding_map)
{
const InputBindingKey& key = it.first;
if (key.source_type == InputSourceType::Pointer && key.source_subtype == InputSubclass::PointerAxis &&
key.data >= static_cast<u32>(InputPointerAxis::X) && key.data <= static_cast<u32>(InputPointerAxis::Y))
{
has_relative_mode_bindings = true;
break;
}
}
}
const bool has_software_cursor = ImGuiManager::HasSoftwareCursor(0);
Host::SetMouseMode(has_relative_mode_bindings, has_relative_mode_bindings || has_software_cursor);
}
bool InputManager::IsUsingRawInput()
@ -1074,22 +1152,6 @@ bool InputManager::IsUsingRawInput()
#endif
}
bool InputManager::HasPointerAxisBinds()
{
std::unique_lock lock(s_binding_map_write_lock);
for (const auto& it : s_binding_map)
{
const InputBindingKey& key = it.first;
if (key.source_type == InputSourceType::Pointer && key.source_subtype == InputSubclass::PointerAxis &&
key.data >= static_cast<u32>(InputPointerAxis::X) && key.data <= static_cast<u32>(InputPointerAxis::Y))
{
return true;
}
}
return false;
}
void InputManager::SetDefaultSourceConfig(SettingsInterface& si)
{
si.ClearSection("InputSources");
@ -1546,6 +1608,7 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
s_binding_map.clear();
s_pad_vibration_array.clear();
s_pointer_move_callbacks.clear();
// Hotkeys use the base configuration, except if the custom hotkeys option is enabled.
const bool use_profile_hotkeys = si.GetBoolValue("ControllerPorts", "UseProfileHotkeyBindings", false);
@ -1573,6 +1636,8 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
default_scale),
1.0f);
}
UpdateHostMouseMode();
}
bool InputManager::MigrateBindings(SettingsInterface& si)

View File

@ -326,9 +326,6 @@ void SetMacroButtonState(u32 pad, u32 index, bool state);
/// Returns true if the raw input source is being used.
bool IsUsingRawInput();
/// Returns true if any bindings are present which require relative mouse movement.
bool HasPointerAxisBinds();
/// Restores default configuration.
void SetDefaultSourceConfig(SettingsInterface& si);
@ -359,4 +356,7 @@ void OnInputDeviceConnected(const std::string_view& identifier, const std::strin
/// Called when an input device is disconnected.
void OnInputDeviceDisconnected(const std::string_view& identifier);
/// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
void SetMouseMode(bool relative, bool hide_cursor);
} // namespace Host