param( [string]$TargetUser = 'User' ) [Console]::OutputEncoding = [Text.Encoding]::UTF8 $ErrorActionPreference = 'Stop' # Resolve target user SID $sid = (New-Object System.Security.Principal.NTAccount($TargetUser)).Translate([System.Security.Principal.SecurityIdentifier]).Value $hivePath = "HKEY_USERS\$sid" $regBase = "Registry::$hivePath" $ntuserDat = "C:\Users\$TargetUser\NTUSER.DAT" $weLoaded = $false if (-not (Test-Path $regBase)) { if (-not (Test-Path $ntuserDat)) { # Try alternate casing (NTFS is case-insensitive but PS sees the literal case) $alt = Get-Item "C:\Users\*" | Where-Object { $_.Name -ieq $TargetUser } | Select-Object -First 1 if ($alt) { $ntuserDat = Join-Path $alt.FullName 'NTUSER.DAT' } } if (-not (Test-Path $ntuserDat)) { throw "NTUSER.DAT not found for $TargetUser" } Write-Host "[*] Loading $ntuserDat" & reg.exe load $hivePath $ntuserDat | Out-Null if ($LASTEXITCODE -ne 0) { throw "reg load failed" } $weLoaded = $true } try { # ---------- 1. Add en-US to language list as FIRST language (default) ---------- # This targets the CURRENT user running this script. For the target user, we # write the preload keys directly into their hive. Write-Host "[*] Setting target user's keyboard preload (en-US first, zh-TW second)" $preloadPath = "$regBase\Keyboard Layout\Preload" if (-not (Test-Path $preloadPath)) { New-Item -Path $preloadPath -Force | Out-Null } # 00000409 = English (US); 00000404 = Chinese (Traditional, Taiwan) New-ItemProperty -Path $preloadPath -Name '1' -Value '00000409' -PropertyType String -Force | Out-Null New-ItemProperty -Path $preloadPath -Name '2' -Value '00000404' -PropertyType String -Force | Out-Null $substitutesPath = "$regBase\Keyboard Layout\Substitutes" if (Test-Path $substitutesPath) { Remove-Item $substitutesPath -Recurse -Force } # ---------- 2. Set Chinese IME to default to English (alphanumeric) mode ---------- Write-Host "[*] Setting Microsoft Bopomofo to default English mode" $chtPath = "$regBase\Software\Microsoft\InputMethod\Settings\CHT" if (-not (Test-Path $chtPath)) { New-Item -Path $chtPath -Force | Out-Null } # 0 = default English mode, 1 = default Chinese mode New-ItemProperty -Path $chtPath -Name 'Enable Default Input Mode' -Value 0 -PropertyType DWord -Force | Out-Null # ---------- 3. Set Bopomofo's Chinese/English switch hotkey to Ctrl+Space ---------- # Microsoft Bopomofo exposes this option in its Settings UI: # Shift (default) | Ctrl + Space | Caps Lock # The registry value is 'Enable Ctrl Space Switch Chinese English' (boolean-ish). Write-Host "[*] Setting Ctrl+Space as Chinese/English switch for MS Bopomofo" New-ItemProperty -Path $chtPath -Name 'Enable Ctrl Space Switch Chinese English' -Value 1 -PropertyType DWord -Force | Out-Null # Also disable Shift as the switch (optional, prevents confusion) New-ItemProperty -Path $chtPath -Name 'Enable Shift Chinese English' -Value 0 -PropertyType DWord -Force | Out-Null # ---------- 4. Disable OS-level Ctrl+Shift / Alt+Shift language toggle ---------- # So Ctrl+Space is the only thing that triggers language switching. Write-Host "[*] Disabling OS-level Language/Layout hotkeys" $togglePath = "$regBase\Keyboard Layout\Toggle" if (-not (Test-Path $togglePath)) { New-Item -Path $togglePath -Force | Out-Null } # Values: 1 = Ctrl+Shift, 2 = Left Alt+Shift, 3 = Grave Accent, 4 = Not assigned New-ItemProperty -Path $togglePath -Name 'Hotkey' -Value '3' -PropertyType String -Force | Out-Null New-ItemProperty -Path $togglePath -Name 'Language Hotkey' -Value '3' -PropertyType String -Force | Out-Null New-ItemProperty -Path $togglePath -Name 'Layout Hotkey' -Value '3' -PropertyType String -Force | Out-Null # ---------- 5. Tell the language subsystem en-US is the default ---------- # Remove user-profile language forcing so that Preload order is respected $userProfileLangPath = "$regBase\Control Panel\International\User Profile" if (Test-Path $userProfileLangPath) { $langs = (Get-ItemProperty $userProfileLangPath).Languages if ($langs) { # Prepend en-US to the language list $newLangs = @('en-US') + ($langs | Where-Object { $_ -ne 'en-US' }) New-ItemProperty -Path $userProfileLangPath -Name 'Languages' -Value $newLangs -PropertyType MultiString -Force | Out-Null Write-Host "[*] Updated user-profile language list: $($newLangs -join ', ')" } } # Ensure per-language subkeys exist $enUSPath = "$userProfileLangPath\en-US" if (-not (Test-Path $enUSPath)) { New-Item -Path $enUSPath -Force | Out-Null } # CachedLanguageName is cosmetic but prevents re-detection flakiness New-ItemProperty -Path $enUSPath -Name '0409:00000409' -Value 1 -PropertyType DWord -Force | Out-Null Write-Host "" Write-Host "[OK] IME configured for '$TargetUser'" Write-Host "Summary:" Write-Host " - Default input: English (US) keyboard" Write-Host " - Microsoft Bopomofo: starts in English (alphanumeric) mode" Write-Host " - Ctrl+Space: toggles between English / Chinese within Bopomofo" Write-Host " - OS-level language hotkeys (Ctrl+Shift / Alt+Shift): disabled" } finally { if ($weLoaded) { [GC]::Collect(); [GC]::WaitForPendingFinalizers() [GC]::Collect(); [GC]::WaitForPendingFinalizers() Start-Sleep -Milliseconds 500 & reg.exe unload $hivePath 2>&1 | Out-Null if ($LASTEXITCODE -eq 0) { Write-Host "[*] Unloaded $hivePath" } else { Write-Host "[!] reg unload returned $LASTEXITCODE" } } } Write-Host "" Write-Host "Note: Settings apply on '$TargetUser' next login. If Bopomofo doesn't pick up" Write-Host "Ctrl+Space automatically, open 'Microsoft Bopomofo settings' -> 'Keys' and" Write-Host "confirm 'Chinese/English switch' = Ctrl+Space (this registry write should do it)."