Added ability to grab the cursor (w/ Windows impl.)

* When grabbed, the mouse cursor may not be moved outside a window's client frame.
 * Fullscreen windows always grab the mouse cursor.
 * The effect is only active while the SFML window is the active
foreground window.
 * Right now this is only implemented for Windows.

Signed-off-by: Marco Antognini <antognini.marco@gmail.com>
This commit is contained in:
Mario Liebisch 2014-05-01 21:08:57 +02:00 committed by Lukas Dürrenberger
parent ba9383f25e
commit f7dcc10a70
10 changed files with 166 additions and 8 deletions

View File

@ -348,6 +348,21 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void setMouseCursorVisible(bool visible); void setMouseCursorVisible(bool visible);
////////////////////////////////////////////////////////////
/// \brief Grab or release the mouse cursor
///
/// If set, grabs the mouse cursor inside this window's client
/// area so it may no longer be moved outside its bounds.
/// Note that grabbing is only active while the window has
/// focus and calling this function for fullscreen windows
/// won't have any effect (fullscreen windows always grab the
/// cursor).
///
/// \param grabbed True to enable, false to disable
///
////////////////////////////////////////////////////////////
void setMouseCursorGrabbed(bool grabbed);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Enable or disable automatic key-repeat /// \brief Enable or disable automatic key-repeat
/// ///

View File

@ -313,6 +313,14 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual void setMouseCursorVisible(bool visible); virtual void setMouseCursorVisible(bool visible);
////////////////////////////////////////////////////////////
/// \brief Grab or release the mouse cursor
///
/// \param grabbed True to enable, false to disable
///
////////////////////////////////////////////////////////////
virtual void setMouseCursorGrabbed(bool grabbed);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Enable or disable automatic key-repeat /// \brief Enable or disable automatic key-repeat
/// ///

View File

@ -486,6 +486,13 @@ void WindowImplCocoa::setMouseCursorVisible(bool visible)
} }
////////////////////////////////////////////////////////////
void WindowImplCocoa::setMouseCursorGrabbed(bool grabbed)
{
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplCocoa::setKeyRepeatEnabled(bool enabled) void WindowImplCocoa::setKeyRepeatEnabled(bool enabled)
{ {

View File

@ -96,6 +96,12 @@ namespace sf {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
-(BOOL)isMouseInside; -(BOOL)isMouseInside;
////////////////////////////////////////////////////////////
/// \brief Grab or release the mouse cursor
///
////////////////////////////////////////////////////////////
-(void)setCursorGrabbed:(bool)grabbed;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Get window position /// \brief Get window position
/// ///

View File

@ -366,7 +366,8 @@ m_hiddenCursor (0),
m_keyRepeat (true), m_keyRepeat (true),
m_previousSize (-1, -1), m_previousSize (-1, -1),
m_useSizeHints (false), m_useSizeHints (false),
m_fullscreen (false) m_fullscreen (false),
m_cursorGrabbed (false)
{ {
// Open a connection with the X server // Open a connection with the X server
m_display = OpenDisplay(); m_display = OpenDisplay();
@ -420,7 +421,8 @@ m_hiddenCursor (0),
m_keyRepeat (true), m_keyRepeat (true),
m_previousSize (-1, -1), m_previousSize (-1, -1),
m_useSizeHints (false), m_useSizeHints (false),
m_fullscreen ((style & Style::Fullscreen) != 0) m_fullscreen ((style & Style::Fullscreen) != 0),
m_cursorGrabbed (m_fullscreen)
{ {
// Open a connection with the X server // Open a connection with the X server
m_display = OpenDisplay(); m_display = OpenDisplay();
@ -952,6 +954,26 @@ void WindowImplX11::setMouseCursorVisible(bool visible)
} }
////////////////////////////////////////////////////////////
void WindowImplX11::setMouseCursorGrabbed(bool grabbed)
{
// This has no effect in fullscreen mode
if (m_fullscreen || (m_cursorGrabbed == grabbed))
return;
if (grabbed)
{
// TODO XGrabPointer(m_display, m_window, true, 0, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
m_cursorGrabbed = true;
}
else
{
// TODO XUngrabPointer(m_display, CurrentTime);
m_cursorGrabbed = false;
}
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::setKeyRepeatEnabled(bool enabled) void WindowImplX11::setKeyRepeatEnabled(bool enabled)
{ {
@ -1661,6 +1683,10 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
if (m_inputContext) if (m_inputContext)
XSetICFocus(m_inputContext); XSetICFocus(m_inputContext);
// Grab cursor
if (m_cursorGrabbed)
;// TODO XGrabPointer(m_display, m_window, true, 0, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime);
Event event; Event event;
event.type = Event::GainedFocus; event.type = Event::GainedFocus;
pushEvent(event); pushEvent(event);
@ -1703,6 +1729,10 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
if (m_inputContext) if (m_inputContext)
XUnsetICFocus(m_inputContext); XUnsetICFocus(m_inputContext);
// Release cursor
if (m_cursorGrabbed)
;// TODO XUngrabPointer(m_display, CurrentTime);
Event event; Event event;
event.type = Event::LostFocus; event.type = Event::LostFocus;
pushEvent(event); pushEvent(event);

View File

@ -147,6 +147,14 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual void setMouseCursorVisible(bool visible); virtual void setMouseCursorVisible(bool visible);
////////////////////////////////////////////////////////////
/// \brief Grab or release the mouse cursor
///
/// \param grabbed True to enable, false to disable
///
////////////////////////////////////////////////////////////
virtual void setMouseCursorGrabbed(bool grabbed);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Enable or disable automatic key-repeat /// \brief Enable or disable automatic key-repeat
/// ///
@ -318,7 +326,8 @@ private:
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled? bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only) Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
bool m_useSizeHints; ///< Is the size of the window fixed with size hints? bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
bool m_fullscreen; ///< Is window in fullscreen? bool m_fullscreen; ///< Is the window in fullscreen?
bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
}; };
} // namespace priv } // namespace priv

View File

@ -132,7 +132,9 @@ m_keyRepeatEnabled(true),
m_lastSize (0, 0), m_lastSize (0, 0),
m_resizing (false), m_resizing (false),
m_surrogate (0), m_surrogate (0),
m_mouseInside (false) m_mouseInside (false),
m_fullscreen (false),
m_cursorGrabbed (false)
{ {
// Set that this process is DPI aware and can handle DPI scaling // Set that this process is DPI aware and can handle DPI scaling
setProcessDpiAware(); setProcessDpiAware();
@ -156,7 +158,9 @@ m_keyRepeatEnabled(true),
m_lastSize (mode.width, mode.height), m_lastSize (mode.width, mode.height),
m_resizing (false), m_resizing (false),
m_surrogate (0), m_surrogate (0),
m_mouseInside (false) m_mouseInside (false),
m_fullscreen (style & Style::Fullscreen),
m_cursorGrabbed (m_fullscreen)
{ {
// Set that this process is DPI aware and can handle DPI scaling // Set that this process is DPI aware and can handle DPI scaling
setProcessDpiAware(); setProcessDpiAware();
@ -187,8 +191,7 @@ m_mouseInside (false)
} }
// In windowed mode, adjust width and height so that window will have the requested client area // In windowed mode, adjust width and height so that window will have the requested client area
bool fullscreen = (style & Style::Fullscreen) != 0; if (!m_fullscreen)
if (!fullscreen)
{ {
RECT rectangle = {0, 0, width, height}; RECT rectangle = {0, 0, width, height};
AdjustWindowRect(&rectangle, win32Style, false); AdjustWindowRect(&rectangle, win32Style, false);
@ -204,7 +207,7 @@ m_mouseInside (false)
setSize(Vector2u(mode.width, mode.height)); setSize(Vector2u(mode.width, mode.height));
// Switch to fullscreen if requested // Switch to fullscreen if requested
if (fullscreen) if (m_fullscreen)
switchToFullscreen(mode); switchToFullscreen(mode);
// Increment window count // Increment window count
@ -277,6 +280,9 @@ Vector2i WindowImplWin32::getPosition() const
void WindowImplWin32::setPosition(const Vector2i& position) void WindowImplWin32::setPosition(const Vector2i& position)
{ {
SetWindowPos(m_handle, NULL, position.x, position.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); SetWindowPos(m_handle, NULL, position.x, position.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
if(m_cursorGrabbed)
grabCursor(true);
} }
@ -363,6 +369,14 @@ void WindowImplWin32::setMouseCursorVisible(bool visible)
} }
////////////////////////////////////////////////////////////
void WindowImplWin32::setMouseCursorGrabbed(bool grabbed)
{
m_cursorGrabbed = grabbed;
grabCursor(m_cursorGrabbed);
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplWin32::setKeyRepeatEnabled(bool enabled) void WindowImplWin32::setKeyRepeatEnabled(bool enabled)
{ {
@ -485,6 +499,23 @@ void WindowImplWin32::setTracking(bool track)
} }
////////////////////////////////////////////////////////////
void WindowImplWin32::grabCursor(bool grabbed)
{
if (grabbed)
{
RECT rect;
GetClientRect(m_handle, &rect);
MapWindowPoints(m_handle, NULL, reinterpret_cast<LPPOINT>(&rect), 2);
ClipCursor(&rect);
}
else
{
ClipCursor(NULL);
}
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam) void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
{ {
@ -536,6 +567,9 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
event.size.width = m_lastSize.x; event.size.width = m_lastSize.x;
event.size.height = m_lastSize.y; event.size.height = m_lastSize.y;
pushEvent(event); pushEvent(event);
// Restore/update cursor grabbing
grabCursor(m_cursorGrabbed);
} }
break; break;
} }
@ -544,6 +578,7 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
case WM_ENTERSIZEMOVE: case WM_ENTERSIZEMOVE:
{ {
m_resizing = true; m_resizing = true;
grabCursor(false);
break; break;
} }
@ -565,6 +600,9 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
event.size.height = m_lastSize.y; event.size.height = m_lastSize.y;
pushEvent(event); pushEvent(event);
} }
// Restore/update cursor grabbing
grabCursor(m_cursorGrabbed);
break; break;
} }
@ -582,6 +620,9 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
// Gain focus event // Gain focus event
case WM_SETFOCUS: case WM_SETFOCUS:
{ {
// Restore cursor grabbing
grabCursor(m_cursorGrabbed);
Event event; Event event;
event.type = Event::GainedFocus; event.type = Event::GainedFocus;
pushEvent(event); pushEvent(event);
@ -591,6 +632,9 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
// Lost focus event // Lost focus event
case WM_KILLFOCUS: case WM_KILLFOCUS:
{ {
// Ungrab the cursor
grabCursor(false);
Event event; Event event;
event.type = Event::LostFocus; event.type = Event::LostFocus;
pushEvent(event); pushEvent(event);

View File

@ -145,6 +145,14 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual void setMouseCursorVisible(bool visible); virtual void setMouseCursorVisible(bool visible);
////////////////////////////////////////////////////////////
/// \brief Grab or release the mouse cursor
///
/// \param grabbed True to enable, false to disable
///
////////////////////////////////////////////////////////////
virtual void setMouseCursorGrabbed(bool grabbed);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Enable or disable automatic key-repeat /// \brief Enable or disable automatic key-repeat
/// ///
@ -216,6 +224,19 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void setTracking(bool track); void setTracking(bool track);
////////////////////////////////////////////////////////////
/// \brief Grab or release the mouse cursor
///
/// This is not to be confused with setMouseCursorGrabbed.
/// Here m_cursorGrabbed is not modified; it is used,
/// for example, to release the cursor when switching to
/// another application.
///
/// \param grabbed True to enable, false to disable
///
////////////////////////////////////////////////////////////
void grabCursor(bool grabbed);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Convert a Win32 virtual key code to a SFML key code /// \brief Convert a Win32 virtual key code to a SFML key code
/// ///
@ -252,6 +273,8 @@ private:
bool m_resizing; ///< Is the window being resized? bool m_resizing; ///< Is the window being resized?
Uint16 m_surrogate; ///< First half of the surrogate pair, in case we're receiving a Unicode character in two events Uint16 m_surrogate; ///< First half of the surrogate pair, in case we're receiving a Unicode character in two events
bool m_mouseInside; ///< Mouse is inside the window? bool m_mouseInside; ///< Mouse is inside the window?
bool m_fullscreen; ///< Is the window fullscreen?
bool m_cursorGrabbed; ///< Is the mouse cursor trapped?
}; };
} // namespace priv } // namespace priv

View File

@ -288,6 +288,14 @@ void Window::setMouseCursorVisible(bool visible)
} }
////////////////////////////////////////////////////////////
void Window::setMouseCursorGrabbed(bool grabbed)
{
if (m_impl)
m_impl->setMouseCursorGrabbed(grabbed);
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Window::setKeyRepeatEnabled(bool enabled) void Window::setKeyRepeatEnabled(bool enabled)
{ {

View File

@ -186,6 +186,14 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
virtual void setMouseCursorVisible(bool visible) = 0; virtual void setMouseCursorVisible(bool visible) = 0;
////////////////////////////////////////////////////////////
/// \brief Grab or release the mouse cursor and keeps it from leaving
///
/// \param grabbed True to enable, false to disable
///
////////////////////////////////////////////////////////////
virtual void setMouseCursorGrabbed(bool grabbed) = 0;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Enable or disable automatic key-repeat /// \brief Enable or disable automatic key-repeat
/// ///