Merge pull request #10858 from AdmiralCurtiss/mouse-center-hotkey

Add hotkey for centering mouse in render window.
This commit is contained in:
Admiral H. Curtiss 2022-07-26 12:52:33 +02:00 committed by GitHub
commit 9d15a1c5a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 108 additions and 32 deletions

View File

@ -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"),

View File

@ -29,6 +29,7 @@ enum Hotkey
HK_SCREENSHOT,
HK_EXIT,
HK_UNLOCK_CURSOR,
HK_CENTER_MOUSE,
HK_ACTIVATE_CHAT,
HK_REQUEST_GOLF_CONTROL,

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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.

View File

@ -108,7 +108,7 @@ private:
private:
void SelectEventsForDevice(XIEventMask* mask, int deviceid);
void UpdateCursor();
void UpdateCursor(bool should_center_mouse);
public:
void UpdateInput() override;