Skip to content

Commit 97bb3dc

Browse files
authored
Fix cursor scheme registration and refresh logic
- Fixed scheme value formatting - Prevented Windows "None" cursor issue - Improved reliability of automatic scheme activation
1 parent 5a0fc12 commit 97bb3dc

File tree

1 file changed

+75
-67
lines changed

1 file changed

+75
-67
lines changed

InstallCursor.ps1

Lines changed: 75 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,81 @@
11
# -------------------------------------------------
2-
# This script sets the "UwU" cursor scheme by:
3-
# 1) Copying cursor files from the "Cursor" folder
4-
# (in the same directory as the script) to
5-
# "C:\Windows\Cursors\MyCustomCursors"
6-
# 2) Updating the Registry to apply them
7-
# 3) Forcing a refresh so the cursors apply immediately
2+
# Custom Cursor Installer - UwU scheme
83
# -------------------------------------------------
4+
# 1) Copies cursor files from .\Cursor (script directory) to:
5+
# C:\Windows\Cursors\MyCustomCursors
6+
# 2) Updates Registry to apply them
7+
# 3) Forces a refresh so the cursors apply immediately
8+
# -------------------------------------------------
9+
10+
[CmdletBinding()]
11+
param(
12+
# Keep old behavior: open Mouse Control Panel by default
13+
[switch]$OpenControlPanel = $true
14+
)
915

16+
$ErrorActionPreference = "Stop"
17+
18+
# [0] Admin check (README says admin required, so fail fast)
19+
# -------------------------------------------------
20+
$principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
21+
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) {
22+
Write-Error "Run PowerShell as Administrator."
23+
exit 1
24+
}
1025

1126
# [1] Copy cursor files
1227
# -------------------------------------------------
13-
$sourceFolder = "$(Get-Location)\Cursor"
28+
$sourceFolder = Join-Path $PSScriptRoot "Cursor"
1429
$targetFolder = "C:\Windows\Cursors\MyCustomCursors"
1530

31+
if (-not (Test-Path $sourceFolder)) {
32+
Write-Error "Source folder not found: $sourceFolder"
33+
exit 1
34+
}
35+
1636
if (-Not (Test-Path $targetFolder)) {
1737
New-Item -ItemType Directory -Path $targetFolder | Out-Null
1838
}
1939

20-
Write-Host "Copying cursors to $targetFolder..."
21-
Copy-Item -Path "$sourceFolder\*" -Destination $targetFolder -Recurse -Force
22-
40+
Write-Host "Copying cursors from $sourceFolder to $targetFolder..."
41+
Copy-Item -Path (Join-Path $sourceFolder "*") -Destination $targetFolder -Force
2342

2443
# [2] Map cursors and set Registry values
2544
# -------------------------------------------------
2645
$cursorMappings = @{
27-
"Arrow" = "$targetFolder\1 Normal Select.ani"
28-
"Help" = "$targetFolder\2 Help Select.ani"
29-
"AppStarting" = "$targetFolder\3 Working in Background.ani"
30-
"Wait" = "$targetFolder\4 Busy.ani"
31-
"Crosshair" = "$targetFolder\5 Precision Select.ani"
32-
"IBeam" = "$targetFolder\6 Text Select.ani"
33-
"NWPen" = "$targetFolder\7 Handwriting.ani"
34-
"No" = "$targetFolder\8 Unavailable.ani"
35-
"SizeNS" = "$targetFolder\9 Vertical Resize.ani"
36-
"SizeWE" = "$targetFolder\10 Horizontal Resize.ani"
37-
"SizeNWSE" = "$targetFolder\11 Diagonal Resize 1.ani"
38-
"SizeNESW" = "$targetFolder\12 Diagonal Resize 2.ani"
39-
"SizeAll" = "$targetFolder\13 Move.ani"
40-
"Hand" = "$targetFolder\15 Link Select.ani"
41-
"UpArrow" = "$targetFolder\14 Alternate Select.ani"
42-
"Pin" = "$targetFolder\16 pin.ani"
43-
"Person" = "$targetFolder\17 person.ani"
46+
"Arrow" = (Join-Path $targetFolder "1 Normal Select.ani")
47+
"Help" = (Join-Path $targetFolder "2 Help Select.ani")
48+
"AppStarting" = (Join-Path $targetFolder "3 Working in Background.ani")
49+
"Wait" = (Join-Path $targetFolder "4 Busy.ani")
50+
"Crosshair" = (Join-Path $targetFolder "5 Precision Select.ani")
51+
"IBeam" = (Join-Path $targetFolder "6 Text Select.ani")
52+
"NWPen" = (Join-Path $targetFolder "7 Handwriting.ani")
53+
"No" = (Join-Path $targetFolder "8 Unavailable.ani")
54+
"SizeNS" = (Join-Path $targetFolder "9 Vertical Resize.ani")
55+
"SizeWE" = (Join-Path $targetFolder "10 Horizontal Resize.ani")
56+
"SizeNWSE" = (Join-Path $targetFolder "11 Diagonal Resize 1.ani")
57+
"SizeNESW" = (Join-Path $targetFolder "12 Diagonal Resize 2.ani")
58+
"SizeAll" = (Join-Path $targetFolder "13 Move.ani")
59+
"UpArrow" = (Join-Path $targetFolder "14 Alternate Select.ani")
60+
"Hand" = (Join-Path $targetFolder "15 Link Select.ani")
61+
"Pin" = (Join-Path $targetFolder "16 pin.ani")
62+
"Person" = (Join-Path $targetFolder "17 person.ani")
63+
}
64+
65+
# Validate files exist BEFORE touching registry
66+
$missing = foreach ($k in $cursorMappings.Keys) {
67+
if (-not (Test-Path $cursorMappings[$k])) { "$k -> $($cursorMappings[$k])" }
68+
}
69+
if ($missing) {
70+
Write-Error "Missing cursor files:`n$($missing -join "`n")"
71+
exit 1
4472
}
4573

4674
Write-Host "Setting system cursor paths..."
4775
foreach ($cursor in $cursorMappings.Keys) {
4876
Set-ItemProperty -Path "HKCU:\Control Panel\Cursors" -Name $cursor -Value $cursorMappings[$cursor]
4977
}
5078

51-
5279
# [3] Create and save the "UwU" scheme
5380
# -------------------------------------------------
5481
Write-Host "Creating the 'UwU' scheme..."
@@ -57,49 +84,36 @@ if (-Not (Test-Path $schemePath)) {
5784
New-Item -Path $schemePath -Force | Out-Null
5885
}
5986

87+
# WYCZYŚĆ STARY WPIS (żeby Windows nie trzymał starego, zepsutego stringa)
88+
Remove-ItemProperty -Path $schemePath -Name "UwU" -ErrorAction SilentlyContinue
89+
6090
# Windows expects a specific order of these 17 entries
61-
$schemeValue = (
62-
$cursorMappings["Arrow"] + "," +
63-
$cursorMappings["Help"] + "," +
64-
$cursorMappings["AppStarting"] + "," +
65-
$cursorMappings["Wait"] + "," +
66-
$cursorMappings["Crosshair"] + "," +
67-
$cursorMappings["IBeam"] + "," +
68-
$cursorMappings["NWPen"] + "," +
69-
$cursorMappings["No"] + "," +
70-
$cursorMappings["SizeNS"] + "," +
71-
$cursorMappings["SizeWE"] + "," +
72-
$cursorMappings["SizeNWSE"] + "," +
73-
$cursorMappings["SizeNESW"] + "," +
74-
$cursorMappings["SizeAll"] + "," +
75-
$cursorMappings["UpArrow"] + "," +
76-
$cursorMappings["Hand"] + "," +
77-
$cursorMappings["Pin"] + "," +
78-
$cursorMappings["Person"]
91+
$order = @(
92+
"Arrow","Help","AppStarting","Wait","Crosshair","IBeam","NWPen","No",
93+
"SizeNS","SizeWE","SizeNWSE","SizeNESW","SizeAll","UpArrow","Hand","Pin","Person"
7994
)
8095

96+
# IMPORTANT: Do NOT quote paths in Schemes value. Windows may treat quotes as part of the path.
97+
$schemeValue = ($order | ForEach-Object { $cursorMappings[$_] }) -join ","
8198
Set-ItemProperty -Path $schemePath -Name "UwU" -Value $schemeValue
8299

83-
# Set the active scheme to "UwU"
100+
# Set active scheme to "UwU" (use reg.exe for default value reliability)
84101
Write-Host "Activating the 'UwU' scheme..."
85-
Set-ItemProperty -Path "HKCU:\Control Panel\Cursors" -Name "(Default)" -Value "UwU"
86-
102+
reg.exe add "HKCU\Control Panel\Cursors" /ve /d "UwU" /f | Out-Null
87103

88-
# [4] Re-sync with the UI (sometimes not necessary, but safer)
104+
# [4] Re-sync with the UI (safer)
89105
# -------------------------------------------------
90106
Write-Host "Synchronizing cursor settings again..."
91107
foreach ($cursor in $cursorMappings.Keys) {
92108
Set-ItemProperty -Path "HKCU:\Control Panel\Cursors" -Name $cursor -Value $cursorMappings[$cursor]
93109
}
94110

95-
96111
# [5] Refresh settings – multiple variants
97112
# -------------------------------------------------
98113
Write-Host "Refreshing cursor settings (rundll32)..."
99114
Rundll32.exe user32.dll, UpdatePerUserSystemParameters
100115

101-
# --- [Optional 1 - But here we keep it active] Stronger refresh via P/Invoke SPI_SETCURSORS ---
102-
# This forces a more thorough system update on some machines
116+
# Stronger refresh via P/Invoke SPI_SETCURSORS
103117
Add-Type -TypeDefinition @"
104118
using System;
105119
using System.Runtime.InteropServices;
@@ -110,26 +124,20 @@ public class NativeMethods {
110124
111125
public static bool RefreshCursors() {
112126
// SPI_SETCURSORS = 0x57
113-
// SPIF_SENDWININICHANGE = 0x02 (sends a system-wide notification)
127+
// SPIF_SENDWININICHANGE = 0x02
114128
return SystemParametersInfo(0x57, 0, null, 0x02);
115129
}
116130
}
117-
"@
131+
"@ | Out-Null
118132

119133
Write-Host "Refreshing cursor settings (SPI_SETCURSORS)..."
120-
[NativeMethods]::RefreshCursors()
121-
122-
123-
# --- [Optional 2] Opening the Mouse Control Panel window ---
124-
# Sometimes just opening the mouse control panel helps Windows
125-
# notice the new scheme (instead of showing None).
126-
Write-Host "Opening Control Panel (optional)..."
127-
Start-Process "rundll32.exe" -ArgumentList "shell32.dll,Control_RunDLL main.cpl @0,1"
128-
129-
# --- [Optional 3] A short pause and another rundll32, if needed ---
130-
# Start-Sleep -Seconds 3
131-
# Rundll32.exe user32.dll, UpdatePerUserSystemParameters
134+
[NativeMethods]::RefreshCursors() | Out-Null
132135

136+
# Optional: open Mouse Control Panel
137+
if ($OpenControlPanel) {
138+
Write-Host "Opening Control Panel (optional)..."
139+
Start-Process "rundll32.exe" -ArgumentList "shell32.dll,Control_RunDLL main.cpl @0,1"
140+
}
133141

134142
# [6] Final message
135143
# -------------------------------------------------

0 commit comments

Comments
 (0)