Ste
Ste

Reputation: 2293

Change and update the size of the cursor in Windows 10 via PowerShell

I've written the code below to affect (what I think) are the only reg keys responsible for the size of the cursor and pointer in Windows 10.

Here's the code I have so far (Some additional comments within):

$RegConnect             = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"CurrentUser", "$env:COMPUTERNAME")
$RegCursorsAccess       = $RegConnect.OpenSubKey("Software\Microsoft\Accessibility", $true)
$RegCursorsControlPanel = $RegConnect.OpenSubKey("Control Panel\Cursors", $true)

# In the code below I'm trying to change the size of the cursor.

$RegCursorsControlPanel.SetValue("CursorBaseSize", 48)
$RegCursorsAccess.SetValue("CursorSize", 3)

$RegCursorsAccess.Close()
$RegConnect.Close()

# This section is where I thought it would update the cursor size.

# Here is where it lists stuff relating to setting and updating any settings changed.
# https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
    # SPI_SETCURSORS
    # 0x0057
    # Reloads the system cursors. Set the uiParam parameter to zero and the pvParam parameter to NULL.

$CSharpSig = @'
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
public static extern bool SystemParametersInfo(
                  uint uiAction,
                  uint uiParam,
                  uint pvParam,
                  uint fWinIni);
'@
$CursorRefresh = Add-Type -MemberDefinition $CSharpSig -Name WinAPICall -Namespace SystemParamInfo -PassThru
$CursorRefresh::SystemParametersInfo(0x0057,0,$null,0)

It will change the correct values in the registry.

So if I run this PowerShell code the mouse size in the ease of access setting is at the correct value.

cursor and pointer size setting

But the cursor doesn't update.

How is it possible to force the update without logging out and back in or restarting the machine.


Here are some related MS links:

WM_SETTINGCHANGE message

SystemParametersInfoA function


EDIT - Some additional info

If I run Process Monitor from Sysinternals and dig deep in there I can see this under the stack summary.

This may lead someone more knowledgeable than me to find how to update the mouse size.

The HKCU\Control Panel\Cursors\(Default) section SettingsHandlers_nt.dll

Sysinternals Process Monitor

And this also for the accessibility section. Windows.UI.Accessibility.dll

Windows.UI.Accessibility.dll

Here are the settings I used in Process Monitors filter to narrow down the items.

Settings used as the filter

Upvotes: 14

Views: 8897

Answers (2)

HaPpY
HaPpY

Reputation: 306

So after a bit of hacking about SystemSettings.exe with cheat engine I found how MS sets the cursor size. It ends up still using SystemParametersInfo but with some undocumented arguments. Try the following :)

SystemParametersInfo(0x2029, 0, 16, 0x01);

to set a cursor size of 16. yup you can go below their minimum of 32, all the way down to 1 :)

Upvotes: 10

Rita Han
Rita Han

Reputation: 9700

But the cursor doesn't update.

After registry value changed, it requires trigger to apply these update.

It can be done using SystemParametersInfo function with SPIF_UPDATEINIFILE and SPIF_SENDCHANGE to writes the new system-wide parameter setting to the user profile and broadcasts the WM_SETTINGCHANGE message after updating the user profile.

SystemParametersInfo(SPI_SETCURSORS, 0, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);

The following is a PowerShell command example:

$RegConnect = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"CurrentUser","$env:COMPUTERNAME")


$RegCursors = $RegConnect.OpenSubKey("Control Panel\Cursors",$true)


$RegCursors.SetValue("","Windows Black")
$RegCursors.SetValue("CursorBaseSize",0x40)

$RegCursors.SetValue("AppStarting","%SystemRoot%\cursors\wait_r.cur")

$RegCursors.SetValue("Arrow","%SystemRoot%\cursors\arrow_rl.cur")

$RegCursors.SetValue("Crosshair","%SystemRoot%\cursors\cross_r.cur")

$RegCursors.SetValue("Hand","")

$RegCursors.SetValue("Help","%SystemRoot%\cursors\help_r.cur")

$RegCursors.SetValue("IBeam","%SystemRoot%\cursors\beam_r.cur")

$RegCursors.SetValue("No","%SystemRoot%\cursors\no_r.cur")

$RegCursors.SetValue("NWPen","%SystemRoot%\cursors\pen_r.cur")

$RegCursors.SetValue("SizeAll","%SystemRoot%\cursors\move_r.cur")

$RegCursors.SetValue("SizeNESW","%SystemRoot%\cursors\size1_r.cur")

$RegCursors.SetValue("SizeNS","%SystemRoot%\cursors\size4_r.cur")

$RegCursors.SetValue("SizeNWSE","%SystemRoot%\cursors\size2_r.cur")

$RegCursors.SetValue("SizeWE","%SystemRoot%\cursors\size3_r.cur")

$RegCursors.SetValue("UpArrow","%SystemRoot%\cursors\up_r.cur")

$RegCursors.SetValue("Wait","%SystemRoot%\cursors\busy_r.cur")

$RegCursors.Close()

$RegConnect.Close()


function Update-UserPreferencesMask {
$Signature = @"
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, uint pvParam, uint fWinIni);

const int SPI_SETCURSORS = 0x0057;
const int SPIF_UPDATEINIFILE = 0x01;
const int SPIF_SENDCHANGE = 0x02;

public static void UpdateUserPreferencesMask() {
    SystemParametersInfo(SPI_SETCURSORS, 0, 0, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
}
"@
    Add-Type -MemberDefinition $Signature -Name UserPreferencesMaskSPI -Namespace User32
    [User32.UserPreferencesMaskSPI]::UpdateUserPreferencesMask()
}
Update-UserPreferencesMask

But unfortunately, the cursor size update doesn't work in this way.

A workaround is using arrow_rl.cur (large image) instead of arrow_r.cur.

Refer to Use PowerShell to Change the Mouse Pointer Scheme, Programmatically change custom mouse cursor in windows.

Upvotes: 2

Related Questions