Hidden mouse inputs and custom cursors

Hidden mouse inputs and custom cursors
0

Hello everyone! So I want to make a custom cursor for desktop platforms. In Mac builds this works flawlessly. I make a sprite with anchor position in it’s center, and then hide the cursor by running
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
glview->setCursorVisible(false);

My problem is when I want to port this code to Win32. The code works, however something crazy happens with the mouse inputs where it is extremely sensitive! You only have to move a little and it crosses the screen. This is not good. If I comment out the code to hide the default cursor, it moves at it’s normal speed.

Has anyone else come across this issue and resolved it, or have ideas? Is there a better method to use for custom cursors?

OK, lots and lots and lots of trial and error, I figured out a work around. I’m documenting this so I don’t forget how I did it, and to help others.

To review, If you want to add a custom cursor sprite by hiding the system cursor and then updating the sprite to the cursor’s position, Windows behaves erratically and the cursor flies by way to fast. Windows does not like to track the cursor position if it is hidden or has no pixels. To fix this, I change the system cursor to a 1 pixel cursor which isn’t ideal, but it works. I can make it the same color as my sprite image that follows the cursor if I want, and offset it to hide it.

To do this, open up the file CCGLViewImpl-desktop.cpp and go to void GLViewImpl::setCursorVisible( bool isVisible )

Change the code to the following:

void GLViewImpl::setCursorVisible( bool isVisible )
{
    if( _mainWindow == NULL )
        return;
    
    if( isVisible )
        glfwSetInputMode(_mainWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
	else {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
		unsigned char pixels[1 * 1 * 4];
		memset(pixels, 0xff, sizeof(pixels));
		GLFWimage image;
		image.width = 1;
		image.height = 1;
		image.pixels = pixels;
		GLFWcursor* cursor = glfwCreateCursor(&image, 0, 0);
		glfwSetCursor(_mainWindow, cursor);
#else
		glfwSetInputMode(_mainWindow, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);

#endif
	}
}

Now, when you hide the cursor, it will instead make the cursor a pixel dot if on win32. However I have a hacked together version of cocos2d-x v 3.17 that allows me to build WinRT projects as well, which uses a different file to hide the cursor. Hiding the cursor works correctly for Xbox, but if I build it for a UWP desktop app, it has the same issue erratic activity.

To solve it, since it seems to use GL ES with Angle to translate to DirectX instead of using OpenGL, we need to do it slightly different.

First we need to create a custom Windows cursor. Then edit a similar function to load it when it typically wants to hide it.

  1. Right click your Game’s project in the Solution Explorer and select Add New Item, select Visual C++ -> Resource->Resource File(.rc). I just left it as Resource.rc
  2. The Solution Explorer switched to Resource View, Right click your newly added resource and click “Add Resource”, select Cursor, and click “New”
  3. Draw whatever you want the cursor to look like… mine again will just be one pixel in the upper left corner.
  4. We need to find out what the Resource ID will be for the cursor. To do this, Go back to the Solution Explorer in Resource View. Right click Resource.rc, or whatever you named it. Select “Resource Symbols”. It should list your cursor and a value. Mine is 101. If you add other cursors this number will change. This is the cursor resource ID.
  5. Change code to Cocos2dEngine/OpenGLESPage.xaml/OpenGLESPage.xaml.cpp, this time the function you want to edit is CreateInput()

void OpenGLESPage::CreateInput()
{
// Register our SwapChainPanel to get independent input pointer events
auto workItemHandler = ref new WorkItemHandler([this](IAsyncAction ^)
{
// The CoreIndependentInputSource will raise pointer events for the specified device types on whichever thread it’s created on.
mCoreInput = swapChainPanel->CreateCoreIndependentInputSource(
Windows::UI::Core::CoreInputDeviceTypes::Mouse |
Windows::UI::Core::CoreInputDeviceTypes::Touch |
Windows::UI::Core::CoreInputDeviceTypes::Pen
);

    // Register for pointer events, which will be raised on the background thread.
    mCoreInput->PointerPressed += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &OpenGLESPage::OnPointerPressed);
    mCoreInput->PointerMoved += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &OpenGLESPage::OnPointerMoved);
    mCoreInput->PointerReleased += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &OpenGLESPage::OnPointerReleased);
    mCoreInput->PointerWheelChanged += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &OpenGLESPage::OnPointerWheelChanged);

    if (GLViewImpl::sharedOpenGLView() && !GLViewImpl::sharedOpenGLView()->isCursorVisible())
    {
  	if (Windows::System::Profile::AnalyticsInfo::VersionInfo->DeviceFamily == "Windows.Desktop") {
  		Windows::UI::Core::CoreCursorType cursorType = Windows::UI::Core::CoreCursorType::Custom;
  		Windows::UI::Core::CoreCursor ^* theCursor = new Windows::UI::Core::CoreCursor ^ (nullptr);
  		*theCursor = ref new Windows::UI::Core::CoreCursor(cursorType, 101); //101 is the resource id number for my cursor
  		mCoreInput->PointerCursor = *theCursor;
  	}
  	else {
  		mCoreInput->PointerCursor = nullptr;
  	}
       
    }

  // Begin processing input messages as they're delivered.
    mCoreInput->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
});

// Run task on a dedicated high priority background thread.
mInputLoopWorker = ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::TimeSliced);

}

2 Likes

sorry I didn’t response earlier. I believe they’ve added a function in cocos2d-x 3.17.1 to change mouse cursor.

Lol that figures. Though I can’t update to 3.17.1 due to my custom hacked version to compile for WinRT since they discontinued WinRT support. I tried getting 3.17.1 to work but I think they changed too much for me to get WinRT working with it - tho someone smarter than me may be able to get it working. I may be able to hack my version of 3.17 more with whatever function was added for setting the cursor if it works better… I’ll play with it. If not, I have my workaround!

Looked into this, and I’m still working on upgrading my project to 3.17.1 - just finished hacking 3.17.1 to build Win10 projects, but because Win10/UWP apps use GL ES / Angle to DirectX, instead of GLFW I still need to do the same solution for UWP that I posted above, but for everything else, the new setcursor() function in 3.17.1 will work great. It basically does what I did by making a custom OpenGL cursor. But instead of making a 1x1 pixel cursor instead it makes the cursor the image that you specify. I was on the right track to figuring that out!

I actually didn’t use the change cursor function due to some problems… I basically made a sprite and kept it on the same position. plus i needed an animated cursor so that was the way to go.

Could you solve the problem of having an animated cursor? I currently have the cursor image change functioned but I wanted to add this possibility.