pomelo
pomelo

Reputation: 31

SetCursor doesn't work

I'm working on a Windows application using SDL2. I want to change the cursor display. I created the cursor using the sample, exactly copied, from SDL_CreateCursor and then invoke SDL_SetCursor within the SDL_MOUSEMOTION event, but it seems no luck.

So I just jump into:

SDL_Cursor * cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); 
SDL_SetCursor(cursor); 

where the official wiki reports SDL_CreateSystemCursor to a TODO state. I looked into the sources, it seems had been implemented and a valid cursor could be created. However, the cursor display did not change neither.

What should I do?

Upvotes: 2

Views: 2923

Answers (3)

Tron
Tron

Reputation: 21

Nine years after your question, here I was searching for a response for this because I had the same problem. My problem, and I'm secure that yours too, was the following: I created a SDL_Window from an existing HWND window by means of SDL_CreateWindowFrom. The existing HWND window was firstly registered with RegisterClassEx and configured to have a crosshair as a mouse pointer.

Later, the SDL_Window from the existing HWND was created, and when I moved the mouse pointer into the window, it changed momentarily to an arrow and immediately to a crosshair. For this does not happen, after the creation of the SDL_Window I added:

SDL_Cursor* cursor;
cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
SDL_SetCursor(cursor);

Here is the complete code:

#include <SDL.h>
#include <SDL_syswm.h>
#include <iostream>

#define WINDOW_CLASS_NAME L"WindowClassName"
#define APP_ICON L"AppIcon.ico"

UINT const WMAPP_NOTIFYCALLBACK = WM_APP + 1;
HINSTANCE g_hInst = NULL;

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WMAPP_NOTIFYCALLBACK:
        switch (lParam)
        {
        case WM_RBUTTONUP:
            // Right mouse button upped
            break;
        case WM_MBUTTONUP:
            // Middle button upped
            break;
        case WM_LBUTTONUP:
            // Left button upped
            break;
        }
        break;
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

void RegisterWindowClass(PCWSTR pszClassName, PCWSTR pszMenuName, WNDPROC lpfnWndProc)
{
    WNDCLASSEX wcex = { sizeof(wcex) };
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = lpfnWndProc;
    wcex.hInstance = g_hInst;
    wcex.hIcon = LoadIcon(g_hInst, APP_ICON);
    wcex.hCursor = LoadCursor(NULL, IDC_CROSS);  // <-- CROSSHAIR AS MOUSE POINTER
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = pszMenuName;
    wcex.lpszClassName = pszClassName;
    RegisterClassEx(&wcex);
}

int main(int argc, char* argv[])
{
    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        std::cout << "SDL_Init error: " << SDL_GetError() << std::endl;
        return 1;
    }

    g_hInst = GetModuleHandle(NULL);
    RegisterWindowClass(WINDOW_CLASS_NAME, NULL, WndProc);

    HWND hwnd = CreateWindow(WINDOW_CLASS_NAME, L"TEST", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, 250, 200, NULL, NULL, g_hInst, NULL);

    SDL_Window* window = SDL_CreateWindowFrom(hwnd);
    SDL_UpdateWindowSurface(window);
    SDL_ShowWindow(window);

    // THIS IS NECESSARY FOR THE MOUSE CURSOR ESTABLISHED IN RegisterWindowClass TO BE MAINTAINED
    SDL_Cursor* cursor;
    cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR);
    SDL_SetCursor(cursor);
    //

    bool running = true;
    SDL_Event e;
    while (running)
    {
        while (SDL_PollEvent(&e))
        {
            if (e.type == SDL_QUIT) running = false;
        }
    }

    SDL_DestroyWindow(window);
    DestroyWindow(hwnd);
    UnregisterClass(WINDOW_CLASS_NAME, g_hInst);
    SDL_Quit();

    return 0;
}

As you can see, once SDL_SetCursor is called, it doesn't have to be called every iteration of the loop.

Upvotes: 2

broderick
broderick

Reputation: 77

There are various issues on GitHub (such as this one) that discuss bugs relating to SDL's cursor setting functions.

You can instead manually create a custom cursor like so:

Declare the mouse object.

int x = 0, y = 0; // The x and y position of the mouse 
Uint32 mouse = SDL_GetMouseState(&x, &y); // Relative to window. 
// Use SDL_GetGlobalMouseState(&x, &y); to get mouse position relative to desktop.

Continuously update the x and y coordinates in your game loop.

mouse = SDL_GetMouseState(&x, &y)

Update a sprite of your choice to follow the x and y coordinate of your mouse.

I recommend you leave the default cursor visible when your implementing this so you can get a feel for any lag / offset and adjust accordingly. When you are happy, you can use the following line to hide the default cursor:

SDL_ShowCursor(SDL_DISABLE);

You can read more on SDL_GetMouseState() here.

Upvotes: 0

PrimitiveType
PrimitiveType

Reputation: 311

You should really post your actual code, but I'm going to take a shot in the dark and see if I can guess what you're doing wrong. You say "I created the cursor using the sample, exactly copied, from SDL_CreateCursor and then invoke SDL_SetCursor within the SDL_MOUSEMOTION event, but it seems no luck." and later you go on to say that it seems to flash to the proper image briefly.

Try changing the SDL cursor BEFORE your even loop. This isn't something you want to run every time the mouse moves, it's something you change as an initialization. Move the code to before the event loop, and AFTER SDL_Init.

If that doesn't work, post your code here so we can actually see what you're doing.

Upvotes: 0

Related Questions