Skip to content
This repository was archived by the owner on Jan 5, 2024. It is now read-only.

Commit d803a45

Browse files
committed
Use better SDL mouse binding routines - now smoothly slides along edges instead of spazzing
Change UInputMan::ForceMouseWithinBox to be relative to the current mouse bounds
1 parent 517668f commit d803a45

File tree

2 files changed

+67
-42
lines changed

2 files changed

+67
-42
lines changed

Managers/UInputMan.cpp

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ namespace RTE {
3838
m_MouseSensitivity = 0.6F;
3939
m_MouseWheelChange = 0;
4040
m_TrapMousePos = false;
41+
m_PlayerScreenMouseBounds = { 0, 0, 0, 0 };
4142
m_MouseTrapRadius = 350;
4243
m_LastDeviceWhichControlledGUICursor = InputDevice::DEVICE_KEYB_ONLY;
4344
m_DisableKeyboard = false;
@@ -120,6 +121,14 @@ namespace RTE {
120121
m_NumJoysticks++;
121122
}
122123
}
124+
125+
m_PlayerScreenMouseBounds = {
126+
0,
127+
0,
128+
g_FrameMan.GetPlayerFrameBufferWidth(Players::NoPlayer) * g_WindowMan.GetResMultiplier(),
129+
g_FrameMan.GetPlayerFrameBufferHeight(Players::NoPlayer) * g_WindowMan.GetResMultiplier()
130+
};
131+
123132
return 0;
124133
}
125134

@@ -372,50 +381,64 @@ namespace RTE {
372381

373382
void UInputMan::ForceMouseWithinBox(int x, int y, int width, int height, int whichPlayer) const {
374383
// Only mess with the mouse if the original mouse position is not above the screen and may be grabbing the title bar of the game window.
375-
if (g_WindowMan.AnyWindowHasFocus() && !m_DisableMouseMoving && !m_TrapMousePos && (whichPlayer == Players::NoPlayer || m_ControlScheme.at(whichPlayer).GetDevice() == InputDevice::DEVICE_MOUSE_KEYB)) {
376-
int mousePosX = m_AbsoluteMousePos.GetFloorIntX();
377-
int mousePosY = m_AbsoluteMousePos.GetFloorIntY();
378-
379-
// -1 because the max mouse position inside the window is -1 its dimensions.
380-
int rightMostPos = x + width - 1;
381-
int bottomMostPos = y + height - 1;
382-
383-
if (mousePosX <= x || mousePosX >= rightMostPos || mousePosY <= y || mousePosY >= bottomMostPos) {
384-
int limitX = std::clamp(mousePosX, x, rightMostPos);
385-
int limitY = std::clamp(mousePosY, y, bottomMostPos);
386-
SDL_WarpMouseInWindow(g_WindowMan.GetWindow(), limitX, limitY);
384+
if (g_WindowMan.AnyWindowHasFocus() && !m_DisableMouseMoving && !m_TrapMousePos && (whichPlayer == Players::NoPlayer || m_ControlScheme[whichPlayer].GetDevice() == InputDevice::DEVICE_MOUSE_KEYB)) {
385+
int rightMostPos = m_PlayerScreenMouseBounds.x + m_PlayerScreenMouseBounds.w;
386+
int bottomMostPos = m_PlayerScreenMouseBounds.y + m_PlayerScreenMouseBounds.h;
387+
388+
SDL_Rect newMouseBounds = {
389+
std::clamp(m_PlayerScreenMouseBounds.x + x, m_PlayerScreenMouseBounds.x, rightMostPos),
390+
std::clamp(m_PlayerScreenMouseBounds.y + y, m_PlayerScreenMouseBounds.y, bottomMostPos),
391+
std::clamp(width, 0, rightMostPos - x),
392+
std::clamp(height, 0, bottomMostPos - y)
393+
};
394+
395+
if (newMouseBounds.x >= rightMostPos || newMouseBounds.y >= bottomMostPos) {
396+
g_ConsoleMan.PrintString("ERROR: Trying to force mouse wihin a box that is outside the player screen bounds!");
397+
newMouseBounds = m_PlayerScreenMouseBounds;
387398
}
399+
SDL_SetWindowMouseRect(g_WindowMan.GetWindow(), &newMouseBounds);
388400
}
389401
}
390402

391403
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
392404

393-
void UInputMan::ForceMouseWithinPlayerScreen(int whichPlayer) const {
394-
if (whichPlayer >= Players::PlayerOne && whichPlayer < Players::MaxPlayerCount) {
395-
int screenWidth = g_FrameMan.GetPlayerFrameBufferWidth(whichPlayer) * g_WindowMan.GetResMultiplier();
396-
int screenHeight = g_FrameMan.GetPlayerFrameBufferHeight(whichPlayer) * g_WindowMan.GetResMultiplier();
405+
void UInputMan::ForceMouseWithinPlayerScreen(bool force, int whichPlayer) {
406+
int resMultiplier = g_WindowMan.GetResMultiplier();
407+
408+
if (force && (whichPlayer >= Players::PlayerOne && whichPlayer < Players::MaxPlayerCount)) {
409+
int screenWidth = g_FrameMan.GetPlayerFrameBufferWidth(whichPlayer) * resMultiplier;
410+
int screenHeight = g_FrameMan.GetPlayerFrameBufferHeight(whichPlayer) * resMultiplier;
397411

398412
switch (g_ActivityMan.GetActivity()->ScreenOfPlayer(whichPlayer)) {
399413
case 0:
400-
ForceMouseWithinBox(0, 0, screenWidth, screenHeight, whichPlayer);
414+
m_PlayerScreenMouseBounds = { 0, 0, screenWidth, screenHeight };
401415
break;
402416
case 1:
403417
if (g_FrameMan.GetVSplit()) {
404-
ForceMouseWithinBox(screenWidth, 0, screenWidth, screenHeight, whichPlayer);
418+
m_PlayerScreenMouseBounds = { screenWidth, 0, screenWidth, screenHeight };
405419
} else {
406-
ForceMouseWithinBox(0, screenHeight, screenWidth, screenHeight, whichPlayer);
420+
m_PlayerScreenMouseBounds = { 0, screenHeight, screenWidth, screenHeight };
407421
}
408422
break;
409423
case 2:
410-
ForceMouseWithinBox(0, screenHeight, screenWidth, screenHeight, whichPlayer);
424+
m_PlayerScreenMouseBounds = { 0, screenHeight, screenWidth, screenHeight };
411425
break;
412426
case 3:
413-
ForceMouseWithinBox(screenWidth, screenHeight, screenWidth, screenHeight, whichPlayer);
427+
m_PlayerScreenMouseBounds = { screenWidth, screenHeight, screenWidth, screenHeight };
414428
break;
415429
default:
416-
// ScreenOfPlayer will return -1 for inactive player so do nothing.
417-
break;
430+
force = false;
418431
}
432+
} else {
433+
force = false;
434+
}
435+
436+
if (force) {
437+
SDL_SetWindowMouseRect(g_WindowMan.GetWindow(), &m_PlayerScreenMouseBounds);
438+
} else {
439+
// Set the mouse bounds to the whole window so ForceMouseWithinBox is not stuck being relative to some player screen, because it can still bind the mouse even if this doesn't.
440+
m_PlayerScreenMouseBounds = { 0, 0, g_WindowMan.GetResX() * resMultiplier, g_WindowMan.GetResY() * resMultiplier };
441+
SDL_SetWindowMouseRect(g_WindowMan.GetWindow(), nullptr);
419442
}
420443
}
421444

@@ -982,14 +1005,9 @@ namespace RTE {
9821005
m_AnalogMouseData.CapMagnitude(m_MouseTrapRadius);
9831006

9841007
// Only mess with the mouse pos if the original mouse position is not above the screen and may be grabbing the title bar of the game window
985-
if (!m_DisableMouseMoving && !IsInMultiplayerMode()) {
986-
if (m_TrapMousePos && g_WindowMan.AnyWindowHasFocus()) {
987-
// Trap the (invisible) mouse cursor in the middle of the screen, so it doesn't fly out in windowed mode and some other window gets clicked
988-
// SDL_WarpMouseInWindow(g_FrameMan.GetWindow(), g_WindowMan.GetResX() / 2, g_WindowMan.GetResY() / 2);
989-
} else if (g_ActivityMan.IsInActivity()) {
990-
// The mouse cursor is visible and can move about the screen/window, but it should still be contained within the mouse player's part of the window
991-
ForceMouseWithinPlayerScreen(mousePlayer);
992-
}
1008+
if (g_WindowMan.AnyWindowHasFocus() && !IsInMultiplayerMode() && !m_DisableMouseMoving && !m_TrapMousePos) {
1009+
// The mouse cursor is visible and can move about the screen/window, but it should still be contained within the mouse player's part of the window
1010+
ForceMouseWithinPlayerScreen(g_ActivityMan.IsInActivity(), mousePlayer);
9931011
}
9941012

9951013
// Enable the mouse cursor positioning again after having been disabled. Only do this when the mouse is within the drawing area so it

Managers/UInputMan.h

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
#define g_UInputMan UInputMan::Instance()
1212

13+
extern "C" {
14+
struct SDL_Rect;
15+
}
16+
1317
namespace RTE {
1418

1519
class Icon;
@@ -411,20 +415,12 @@ namespace RTE {
411415
/// <summary>
412416
/// Forces the mouse within a box on the screen.
413417
/// </summary>
414-
/// <param name="x">X value of the top left corner of the screen box to keep the mouse within, in screen coordinates.</param>
415-
/// <param name="y">Y value of the top left corner of the screen box to keep the mouse within, in screen coordinates.</param>
418+
/// <param name="x">X value of the top left corner of the screen box to keep the mouse within, relative to the top left corner of the player's screen.</param>
419+
/// <param name="y">Y value of the top left corner of the screen box to keep the mouse within, relative to the top left corner of the player's screen.</param>
416420
/// <param name="width">The width of the box.</param>
417421
/// <param name="height">The height of the box.</param>
418422
/// <param name="whichPlayer">Which player is trying to control the mouse. Only the player with actual control over the mouse will be affected. -1 means do it regardless of player.</param>
419-
void ForceMouseWithinBox(int x, int y, int width, int height, int whichPlayer = -1) const;
420-
421-
/// <summary>
422-
/// Forces the mouse within a specific player's screen area.
423-
/// Player 1 will always be in the upper-left corner, Player 3 will always be in the lower-left corner, Player 4 will always be in the lower-right quadrant.
424-
/// Player 2 will either be in the lower-left corner or the upper-right corner depending on vertical/horizontal splitting.
425-
/// </summary>
426-
/// <param name="whichPlayer">Which player's screen to constrain the mouse to. Only the player with actual control over the mouse will be affected.</param>
427-
void ForceMouseWithinPlayerScreen(int whichPlayer) const;
423+
void ForceMouseWithinBox(int x, int y, int width, int height, int whichPlayer = Players::NoPlayer) const;
428424
#pragma endregion
429425

430426
#pragma region Joystick Handling
@@ -689,6 +685,7 @@ namespace RTE {
689685

690686
bool m_TrapMousePos; //!< Whether the mouse is trapped in the middle of the screen each update or not.
691687
float m_MouseTrapRadius; //!< The radius (in pixels) of the circle trapping the mouse for analog mouse data.
688+
SDL_Rect m_PlayerScreenMouseBounds; //!< Rect with the position and dimensions of the player screen that the mouse is bound to, when bounding is enabled.
692689

693690
InputDevice m_LastDeviceWhichControlledGUICursor; //!< Indicates which device controlled the cursor last time.
694691

@@ -715,6 +712,16 @@ namespace RTE {
715712
static constexpr int c_AxisDigitalPressedThreshold = 8192; //!< Digital Axis threshold value as defined by allegro.
716713
static constexpr int c_AxisDigitalReleasedThreshold = c_AxisDigitalPressedThreshold - 100; //!< Digital Axis release threshold, to debounce values.
717714

715+
#pragma region Mouse Handling
716+
/// <summary>
717+
/// Forces the mouse within a specific player's screen area.
718+
/// Player 1 will always be in the upper-left corner, Player 3 will always be in the lower-left corner, Player 4 will always be in the lower-right quadrant.
719+
/// Player 2 will either be in the lower-left corner or the upper-right corner depending on vertical/horizontal splitting.
720+
/// </summary>
721+
/// <param name="whichPlayer">Which player's screen to constrain the mouse to. Only the player with actual control over the mouse will be affected.</param>
722+
void ForceMouseWithinPlayerScreen(bool force, int whichPlayer);
723+
#pragma endregion
724+
718725
#pragma region Input State Handling
719726
/// <summary>
720727
/// Gets whether an input element is in the specified state.

0 commit comments

Comments
 (0)