GunCon: Add relative pointer binding
This commit is contained in:
@ -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)
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user