@mystical
I haven’t tested on other Windows, but should work I guess.
In libcocos2d/platform/desktop/CCGLViewImpl-desktop.h, add
bool _cursorLocked;
I added in protected field after _mouseY variable.
Also add
/**
* Lock or Unlock the system cursor
*/
void setCursorLock(const bool isLocked);
in public field. I added after setCursorVisible(bool) function.
In libcocos2d/platform/desktop/CCGLViewImp-desktop.cpp
Initialize _cursorLocked in constructor
GLViewImpl::GLViewImpl(bool initglfw)
: _captured(false)
, _supportTouch(false)
, _isInRetinaMonitor(false)
, _isRetinaEnabled(false)
, _retinaFactor(1)
, _frameZoomFactor(1.0f)
, _mainWindow(nullptr)
, _monitor(nullptr)
, _mouseX(0.0f)
, _mouseY(0.0f)
, _cursorLocked(false) <- here
{
//....
}
Then add setCursorLock(bool) function.
void GLViewImpl::setCursorLock(bool isLocked)
{
// Return if window is null
if (_mainWindow == NULL)
return;
_cursorLocked = isLocked;
if (isLocked)
{
// Client rect area. This excludes border, caption, etc. Only gets the inner window area.
RECT clientRect;
GetClientRect(glfwGetWin32Window(_mainWindow), &clientRect);
// Rect to points.
POINT leftTop, rightBottomn;
leftTop.x = clientRect.left;
leftTop.y = clientRect.top;
rightBottomn.x = clientRect.right;
rightBottomn.y = clientRect.bottom;
// Since clientRect starts at (0, 0), we need to convert points to screen position.
HWND hwnd = glfwGetWin32Window(_mainWindow);
ClientToScreen(hwnd, &leftTop);
ClientToScreen(hwnd, &rightBottomn);
/*
// Note: Uncomment this block to include title bar to clien rect. This will let user move around window while Windowed mode.
if (!isFullscreen())
{
// Get caption height and apply to point
int captionHeight = (GetSystemMetrics(SM_CYFRAME) + GetSystemMetrics(SM_CYCAPTION) +
GetSystemMetrics(SM_CXPADDEDBORDER));
leftTop.y -= captionHeight;
}
*/
// Set client Rect to screen point.
clientRect.left = leftTop.x;
clientRect.top = leftTop.y;
clientRect.right = rightBottomn.x;
clientRect.bottom = rightBottomn.y;
// Lock cursor in this area
ClipCursor(&clientRect);
}
else
{
// Disable lock
ClipCursor(NULL);
}
}
I found that ClipCursor disappears when window is moved, resized, etc. So we need to reset every time when that happens
Add
if (_cursorLocked)
{
// Reset cursor lock when window move.
setCursorLock(true);
}
this to
void GLViewImpl::onGLFWWindowPosCallback(GLFWwindow* /*window*/, int /*x*/, int /*y*/)
{
Director::getInstance()->setViewport();
if (_cursorLocked)
{
// Reset cursor lock when window move.
setCursorLock(true);
}
}
and
void GLViewImpl::onGLFWframebuffersize(GLFWwindow* window, int w, int h)
{
//.....
if (_cursorLocked)
{
// Reset cursor lock when frame buffer size changes
setCursorLock(true);
}
}
and
void GLViewImpl::onGLFWWindowSizeFunCallback(GLFWwindow* /*window*/, int width, int height)
{
if (width && height && _resolutionPolicy != ResolutionPolicy::UNKNOWN)
{
//....
if (_cursorLocked)
{
// Reset cursor lock when window size changes
setCursorLock(true);
}
}
}
and
void GLViewImpl::onGLFWWindowFocusCallback(GLFWwindow* /*window*/, int focused)
{
if (focused == GL_TRUE)
{
Director::getInstance()->getEventDispatcher()->dispatchCustomEvent(GLViewImpl::EVENT_WINDOW_FOCUSED, nullptr);
// Reset cursor lock when window gets focused back.
if (_cursorLocked)
{
setCursorLock(true);
}
}
else
{
Director::getInstance()->getEventDispatcher()->dispatchCustomEvent(GLViewImpl::EVENT_WINDOW_UNFOCUSED, nullptr);
// Don't need to unlock cursor when focus is lost. Lock automatically released.
}
}
If you want the code to run only on Win32, you can wrap above codes with
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
//...
#endif
but it’s unnecessary if cross-platform is not a thing.
I might missed corner cases, but I think this is it.