Merge pull request #10858 from AdmiralCurtiss/mouse-center-hotkey
Add hotkey for centering mouse in render window.
This commit is contained in:
commit
9d15a1c5a1
|
@ -35,6 +35,7 @@ constexpr std::array<const char*, NUM_HOTKEYS> s_hotkey_labels{{
|
|||
_trans("Take Screenshot"),
|
||||
_trans("Exit"),
|
||||
_trans("Unlock Cursor"),
|
||||
_trans("Center Mouse"),
|
||||
_trans("Activate NetPlay Chat"),
|
||||
_trans("Control NetPlay Golf Mode"),
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ enum Hotkey
|
|||
HK_SCREENSHOT,
|
||||
HK_EXIT,
|
||||
HK_UNLOCK_CURSOR,
|
||||
HK_CENTER_MOUSE,
|
||||
HK_ACTIVATE_CHAT,
|
||||
HK_REQUEST_GOLF_CONTROL,
|
||||
|
||||
|
|
|
@ -233,6 +233,9 @@ void HotkeyScheduler::Run()
|
|||
if (IsHotkey(HK_UNLOCK_CURSOR))
|
||||
emit UnlockCursor();
|
||||
|
||||
if (IsHotkey(HK_CENTER_MOUSE, true))
|
||||
g_controller_interface.SetMouseCenteringRequested(true);
|
||||
|
||||
auto& settings = Settings::Instance();
|
||||
|
||||
// Toggle Chat
|
||||
|
|
|
@ -421,6 +421,16 @@ Common::Vec2 ControllerInterface::GetWindowInputScale() const
|
|||
return {1 / ar, 1.f};
|
||||
}
|
||||
|
||||
void ControllerInterface::SetMouseCenteringRequested(bool center)
|
||||
{
|
||||
m_requested_mouse_centering = center;
|
||||
}
|
||||
|
||||
bool ControllerInterface::IsMouseCenteringRequested() const
|
||||
{
|
||||
return m_requested_mouse_centering.load();
|
||||
}
|
||||
|
||||
// Register a callback to be called when a device is added or removed (as from the input backends'
|
||||
// hotplug thread), or when devices are refreshed
|
||||
// Returns a handle for later removing the callback.
|
||||
|
|
|
@ -106,6 +106,11 @@ public:
|
|||
// Inputs based on window coordinates should be multiplied by this.
|
||||
Common::Vec2 GetWindowInputScale() const;
|
||||
|
||||
// Request that the mouse cursor should be centered in the render window at the next opportunity.
|
||||
void SetMouseCenteringRequested(bool center);
|
||||
|
||||
bool IsMouseCenteringRequested() const;
|
||||
|
||||
HotplugCallbackHandle RegisterDevicesChangedCallback(std::function<void(void)> callback);
|
||||
void UnregisterDevicesChangedCallback(const HotplugCallbackHandle& handle);
|
||||
void InvokeDevicesChangedCallbacks() const;
|
||||
|
@ -127,6 +132,7 @@ private:
|
|||
std::atomic<int> m_populating_devices_counter;
|
||||
WindowSystemInfo m_wsi;
|
||||
std::atomic<float> m_aspect_ratio_adjustment = 1;
|
||||
std::atomic<bool> m_requested_mouse_centering = false;
|
||||
};
|
||||
|
||||
namespace ciface
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/Host.h"
|
||||
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
#include "InputCommon/ControllerInterface/DInput/DInput.h"
|
||||
|
@ -168,13 +170,6 @@ KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device,
|
|||
|
||||
void KeyboardMouse::UpdateCursorInput()
|
||||
{
|
||||
POINT point = {};
|
||||
GetCursorPos(&point);
|
||||
|
||||
// Get the cursor position relative to the upper left corner of the current window
|
||||
// (separate or render to main)
|
||||
ScreenToClient(s_hwnd, &point);
|
||||
|
||||
// Get the size of the current window (in my case Rect.top and Rect.left was zero).
|
||||
RECT rect;
|
||||
GetClientRect(s_hwnd, &rect);
|
||||
|
@ -183,6 +178,26 @@ void KeyboardMouse::UpdateCursorInput()
|
|||
const auto win_width = std::max(rect.right - rect.left, 1l);
|
||||
const auto win_height = std::max(rect.bottom - rect.top, 1l);
|
||||
|
||||
POINT point = {};
|
||||
if (g_controller_interface.IsMouseCenteringRequested() && Host_RendererHasFocus())
|
||||
{
|
||||
point.x = win_width / 2;
|
||||
point.y = win_height / 2;
|
||||
|
||||
POINT screen_point = point;
|
||||
ClientToScreen(s_hwnd, &screen_point);
|
||||
SetCursorPos(screen_point.x, screen_point.y);
|
||||
g_controller_interface.SetMouseCenteringRequested(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetCursorPos(&point);
|
||||
|
||||
// Get the cursor position relative to the upper left corner of the current window
|
||||
// (separate or render to main)
|
||||
ScreenToClient(s_hwnd, &point);
|
||||
}
|
||||
|
||||
const auto window_scale = g_controller_interface.GetWindowInputScale();
|
||||
|
||||
// Convert the cursor position to a range from -1 to 1.
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <Carbon/Carbon.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
#include "Core/Host.h"
|
||||
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
|
||||
namespace ciface::Quartz
|
||||
|
@ -192,16 +194,36 @@ void KeyboardAndMouse::UpdateInput()
|
|||
CFRelease(windowDescriptions);
|
||||
CFRelease(windowArray);
|
||||
|
||||
CGEventRef event = CGEventCreate(nil);
|
||||
CGPoint loc = CGEventGetLocation(event);
|
||||
CFRelease(event);
|
||||
const double window_width = std::max(bounds.size.width, 1.0);
|
||||
const double window_height = std::max(bounds.size.height, 1.0);
|
||||
|
||||
const auto window_scale = g_controller_interface.GetWindowInputScale();
|
||||
if (g_controller_interface.IsMouseCenteringRequested() && Host_RendererHasFocus())
|
||||
{
|
||||
m_cursor.x = 0;
|
||||
m_cursor.y = 0;
|
||||
|
||||
loc.x -= bounds.origin.x;
|
||||
loc.y -= bounds.origin.y;
|
||||
m_cursor.x = (loc.x / std::max(bounds.size.width, 1.0) * 2 - 1.0) * window_scale.x;
|
||||
m_cursor.y = (loc.y / std::max(bounds.size.height, 1.0) * 2 - 1.0) * window_scale.y;
|
||||
const CGPoint window_center_global_coordinates =
|
||||
CGPointMake(bounds.origin.x + window_width / 2.0, bounds.origin.y + window_height / 2.0);
|
||||
CGWarpMouseCursorPosition(window_center_global_coordinates);
|
||||
// Without this line there is a short but obvious delay after centering the cursor before it can
|
||||
// be moved again
|
||||
CGAssociateMouseAndMouseCursorPosition(true);
|
||||
|
||||
g_controller_interface.SetMouseCenteringRequested(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
CGEventRef event = CGEventCreate(nil);
|
||||
CGPoint loc = CGEventGetLocation(event);
|
||||
CFRelease(event);
|
||||
|
||||
const auto window_scale = g_controller_interface.GetWindowInputScale();
|
||||
|
||||
loc.x -= bounds.origin.x;
|
||||
loc.y -= bounds.origin.y;
|
||||
m_cursor.x = (loc.x / window_width * 2 - 1.0) * window_scale.x;
|
||||
m_cursor.y = (loc.y / window_height * 2 - 1.0) * window_scale.y;
|
||||
}
|
||||
}
|
||||
|
||||
std::string KeyboardAndMouse::GetName() const
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/Host.h"
|
||||
|
||||
// This is an input plugin using the XInput 2.0 extension to the X11 protocol,
|
||||
// loosely based on the old XLib plugin. (Has nothing to do with the XInput
|
||||
// API on Windows.)
|
||||
|
@ -209,30 +211,44 @@ KeyboardMouse::~KeyboardMouse()
|
|||
}
|
||||
|
||||
// Update the mouse cursor controls
|
||||
void KeyboardMouse::UpdateCursor()
|
||||
void KeyboardMouse::UpdateCursor(bool should_center_mouse)
|
||||
{
|
||||
double root_x, root_y, win_x, win_y;
|
||||
Window root, child;
|
||||
|
||||
// unused-- we're not interested in button presses here, as those are
|
||||
// updated using events
|
||||
XIButtonState button_state;
|
||||
XIModifierState mods;
|
||||
XIGroupState group;
|
||||
|
||||
XIQueryPointer(m_display, pointer_deviceid, m_window, &root, &child, &root_x, &root_y, &win_x,
|
||||
&win_y, &button_state, &mods, &group);
|
||||
|
||||
free(button_state.mask);
|
||||
|
||||
XWindowAttributes win_attribs;
|
||||
XGetWindowAttributes(m_display, m_window, &win_attribs);
|
||||
const auto win_width = std::max(win_attribs.width, 1);
|
||||
const auto win_height = std::max(win_attribs.height, 1);
|
||||
|
||||
if (should_center_mouse)
|
||||
{
|
||||
win_x = win_width / 2;
|
||||
win_y = win_height / 2;
|
||||
|
||||
XIWarpPointer(m_display, pointer_deviceid, None, m_window, 0.0, 0.0, 0, 0, win_x, win_y);
|
||||
|
||||
g_controller_interface.SetMouseCenteringRequested(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unused-- we're not interested in button presses here, as those are
|
||||
// updated using events
|
||||
XIButtonState button_state;
|
||||
XIModifierState mods;
|
||||
XIGroupState group;
|
||||
|
||||
XIQueryPointer(m_display, pointer_deviceid, m_window, &root, &child, &root_x, &root_y, &win_x,
|
||||
&win_y, &button_state, &mods, &group);
|
||||
|
||||
free(button_state.mask);
|
||||
}
|
||||
|
||||
const auto window_scale = g_controller_interface.GetWindowInputScale();
|
||||
|
||||
// the mouse position as a range from -1 to 1
|
||||
m_state.cursor.x = (win_x / std::max(win_attribs.width, 1) * 2 - 1) * window_scale.x;
|
||||
m_state.cursor.y = (win_y / std::max(win_attribs.height, 1) * 2 - 1) * window_scale.y;
|
||||
m_state.cursor.x = (win_x / win_width * 2 - 1) * window_scale.x;
|
||||
m_state.cursor.y = (win_y / win_height * 2 - 1) * window_scale.y;
|
||||
}
|
||||
|
||||
void KeyboardMouse::UpdateInput()
|
||||
|
@ -318,8 +334,10 @@ void KeyboardMouse::UpdateInput()
|
|||
m_state.axis.y /= MOUSE_AXIS_SMOOTHING + 1.0f;
|
||||
|
||||
// Get the absolute position of the mouse pointer
|
||||
if (mouse_moved)
|
||||
UpdateCursor();
|
||||
const bool should_center_mouse =
|
||||
g_controller_interface.IsMouseCenteringRequested() && Host_RendererHasFocus();
|
||||
if (mouse_moved || should_center_mouse)
|
||||
UpdateCursor(should_center_mouse);
|
||||
|
||||
// KeyRelease and FocusOut events are sometimes not received.
|
||||
// Cycling Alt-Tab and landing on the same window results in a stuck "Alt" key.
|
||||
|
|
|
@ -108,7 +108,7 @@ private:
|
|||
|
||||
private:
|
||||
void SelectEventsForDevice(XIEventMask* mask, int deviceid);
|
||||
void UpdateCursor();
|
||||
void UpdateCursor(bool should_center_mouse);
|
||||
|
||||
public:
|
||||
void UpdateInput() override;
|
||||
|
|
Loading…
Reference in New Issue