pythonwinapiwin32guiwin32con

How to change cursor image in Python


I want to change my cursor image (everywhere on screen) when my program is running.

I try to load image with win32gui and then use win32api to change cursor image, but something is wrong and my cursor doesn't show up My cursor image is map.cur

import win32api
import time
import win32gui
import win32con

x = win32gui.LoadImage(0,'map.cur',win32con.IMAGE_CURSOR,0,0,win32con.LR_LOADFROMFILE)
win32api.SetCursor(x)

time.sleep(5)

Solution

  • Changing the system cursor is not recommended, because the cursor has to be restored after program exits, and if the program fails then user is stuck with custom cursor and must reset the cursor from system settings.

    For the sake of curiosity, it can be done with SetSystemCursor, example

    ctypes.windll.user32.SetSystemCursor(hcursor, 32512) #OCR_NORMAL
    

    See documentation for OCR_NORMAL and other cursor constants.

    You can try to save the old cursor and restore it, again, this method fails if your program exits abnormally.

    import win32con
    import win32api
    import win32gui
    import ctypes
    import time
    import atexit
    
    #save system cursor, before changing it
    cursor = win32gui.LoadImage(0, 32512, win32con.IMAGE_CURSOR, 
                                0, 0, win32con.LR_SHARED)
    save_system_cursor = ctypes.windll.user32.CopyImage(cursor, win32con.IMAGE_CURSOR, 
                                0, 0, win32con.LR_COPYFROMRESOURCE)
    
    def restore_cursor():
        #restore the old cursor
        print("restore_cursor");
        ctypes.windll.user32.SetSystemCursor(save_system_cursor, 32512)
        ctypes.windll.user32.DestroyCursor(save_system_cursor);
    
    #Make sure cursor is restored at the end
    atexit.register(restore_cursor)
    
    #change system cursor
    cursor = win32gui.LoadImage(0, "file.cur", win32con.IMAGE_CURSOR, 
                                0, 0, win32con.LR_LOADFROMFILE);
    ctypes.windll.user32.SetSystemCursor(cursor, 32512)
    ctypes.windll.user32.DestroyCursor(cursor);
    
    time.sleep(3)
    exit