Last active
March 4, 2024 18:13
-
-
Save sba923/a71dd721e78ae08842616db244f19437 to your computer and use it in GitHub Desktop.
Remove the unwanted keyboard layouts that Windows keeps adding based on input languages
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# this is one of Stéphane BARIZIEN's public domain scripts | |
# the most recent version can be found at: | |
# https://gist.github.com/sba923/a71dd721e78ae08842616db244f19437#file-remove-uselesskeyboardlayouts-ps1 | |
[CmdletBinding()] | |
param([string] $PhysicalKeyboardLayout) | |
$iswinps = ($null, 'Desktop') -contains $PSVersionTable.PSEdition | |
if (!$iswinps) | |
{ | |
Write-Host("This script requires Windows PowerShell, it doesn't run (yet) under PowerShell Core") | |
Exit(1) | |
} | |
$languagelist = Get-WinUserLanguageList | |
# remember what the first entry is | |
$firstlanguage = $languagelist[0].LanguageTag | |
# guess the physical keyboard layout: it should be the layout with the highest | |
# number of occurrences for languages other than English | |
$keyboardlayoutused = @{} | |
for ($languageindex = 0; $languageindex -lt $languagelist.Count; $languageindex++) | |
{ | |
if ($languagelist[$languageindex].LanguageTag -ne 'en-US') | |
{ | |
for ($keyboardlayoutindex = 0; $keyboardlayoutindex -lt $languagelist[$languageindex].InputMethodTips.Count; $keyboardlayoutindex++) | |
{ | |
$keyboardlayout = $languagelist[$languageindex].InputMethodTips[$keyboardlayoutindex] -replace '.*:', '' | |
if ($null -ne $keyboardlayoutused[$keyboardlayout]) | |
{ | |
$keyboardlayoutused[$keyboardlayout]++ | |
} | |
else | |
{ | |
$keyboardlayoutused[$keyboardlayout] = 1 | |
} | |
} | |
} | |
} | |
# if at least one keyboard layout is configured, assume the actual physical keyboard layout | |
# is the one configured for the highest number of input methods, | |
# otherwise use the value of the -PhysicalKeyboardLayout parameter | |
if ($keyboardlayoutused.Keys.Count -ne 0) | |
{ | |
$PhysicalKeyboardLayout = (@( | |
foreach ($k in $keyboardlayoutused.Keys) | |
{ | |
[PSCustomObject] @{ | |
KeyboardLayout = $k | |
Count = $keyboardlayoutused[$k] | |
} | |
}) | Sort-Object -desc count | Select-Object -first 1).KeyboardLayout | |
Write-Verbose ("Assuming physical keyboard layout is {0}" -f $PhysicalKeyboardLayout) | |
} | |
elseif ($PSBoundParameters.ContainsKey('PhysicalKeyboardLayout')) | |
{ | |
Write-Verbose ("Using specified physicaly keyboard layout {0}" -f $PhysicalKeyboardLayout) | |
} | |
else | |
{ | |
throw "Cannot guess the physical keyboard layout, must specify it with -PhysicalKeyboardLayout as 4-hexdigit value." | |
} | |
# make sure there's an entry for the physical keyboard layout for all the configured languages | |
$updateneeded = $false | |
for ($languageindex = 0; $languageindex -lt $languagelist.Count; $languageindex++) | |
{ | |
$physicalkeyboardlayoutconfigured = $false | |
for ($keyboardlayoutindex = 0; $keyboardlayoutindex -lt $languagelist[$languageindex].InputMethodTips.Count; $keyboardlayoutindex++) | |
{ | |
if ($languagelist[$languageindex].InputMethodTips[$keyboardlayoutindex] -match (':' + $PhysicalKeyboardLayout)) | |
{ | |
$physicalkeyboardlayoutconfigured = $true | |
} | |
} | |
if (!$physicalkeyboardlayoutconfigured) | |
{ | |
Write-Verbose ("Adding keyboard layout {0} for language '{1}'" -f $PhysicalKeyboardLayout, $languagelist[$languageindex].LanguageTag) | |
if ($languagelist[$languageindex].InputMethodTips.Count -ge 1) | |
{ | |
$languagelist[$languageindex].InputMethodTips.Add((($languagelist[$languageindex].InputMethodTips[0] -replace ':.*', '') + ':' + $PhysicalKeyboardLayout)) | |
} | |
else | |
{ | |
$languagelist[$languageindex].InputMethodTips.Add(("{0:x4}" -f [System.Globalization.CultureInfo]::GetCultureInfo($languagelist[$languageindex].LanguageTag).LCID).ToUpper() + ':' + $PhysicalKeyboardLayout) | |
} | |
$updateneeded = $true | |
} | |
} | |
if ($updateneeded) | |
{ | |
# make sure the first entry in the list hasn't changed | |
# as it seems Set-WinUserLanguageList sets the Windows UI display language to the first entry in the list | |
if ($languagelist[0].LanguageTag -ne $firstlanguage) | |
{ | |
$newlist = @() | |
$languagelist | Where-Object { $_.LanguageTag -eq $firstlanguage } | ForEach-Object { $newlist += $_ } | |
$languagelist | Where-Object { $_.LanguageTag -ne $firstlanguage } | ForEach-Object { $newlist += $_ } | |
$languagelist = $newlist | |
} | |
Set-WinUserLanguageList -LanguageList $languagelist -Force | |
} | |
# first add the "language = XXX, keyboard layout = default layout for language XXX" if it's not on the list, to make sure removal does remove it 😜 | |
$updateneeded = $false | |
$languagelist.LanguageTag | Foreach-Object { | |
$languagetag = $_ | |
$languagecode = ($languagelist | Where-Object { $_.LanguageTag -eq $languagetag }).InputMethodTips[0].SubString(0, 4) | |
$defaultinputmethod = $languagecode + ':0000' + $languagecode | |
$defaultkeyboardlayout = $defaultinputmethod -replace '^....', '' | |
for ($languageindex = 0; $languageindex -lt $languagelist.Count; $languageindex++) | |
{ | |
if ($languagelist[$languageindex].LanguageTag -eq $languagetag) | |
{ | |
$defaultlayoutpresent = $false | |
for ($keyboardlayoutindex = 0; $keyboardlayoutindex -lt $languagelist[$languageindex].InputMethodTips.Count; $keyboardlayoutindex++) | |
{ | |
if ($languagelist[$languageindex].InputMethodTips[$keyboardlayoutindex] -match $defaultkeyboardlayout) | |
{ | |
$defaultlayoutpresent = $true | |
} | |
} | |
if (!$defaultlayoutpresent) | |
{ | |
Write-Verbose ("Adding input method {0} to ensure proper removal of keyboard layout {1} for language '{2}'" -f $defaultinputmethod, ($defaultinputmethod -replace '.*:', ''), $languagelist[$languageindex].LanguageTag) | |
$languagelist[$languageindex].InputMethodTips.Add($defaultinputmethod) | |
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'updateneeded', Justification = 'variable is used in various scopes throughout the script')] | |
$updateneeded = $true | |
} | |
} | |
} | |
} | |
if ($updateneeded) | |
{ | |
# make sure the first entry in the list hasn't changed | |
# as it seems Set-WinUserLanguageList sets the Windows UI display language to the first entry in the list | |
if ($languagelist[0].LanguageTag -ne $firstlanguage) | |
{ | |
$newlist = @() | |
$languagelist | Where-Object { $_.LanguageTag -eq $firstlanguage } | ForEach-Object { $newlist += $_ } | |
$languagelist | Where-Object { $_.LanguageTag -ne $firstlanguage } | ForEach-Object { $newlist += $_ } | |
$languagelist = $newlist | |
} | |
Set-WinUserLanguageList -LanguageList $languagelist -Force | |
} | |
# now remove the unwanted keyboard layouts | |
$updateneeded = $false | |
for ($languageindex = 0; $languageindex -lt $languagelist.Count; $languageindex++) | |
{ | |
for ($keyboardlayoutindex = 0; $keyboardlayoutindex -lt $languagelist[$languageindex].InputMethodTips.Count; $keyboardlayoutindex++) | |
{ | |
if ($languagelist[$languageindex].InputMethodTips[$keyboardlayoutindex] -notmatch (':' + $PhysicalKeyboardLayout)) | |
{ | |
Write-Verbose ("Removing keyboard layout {0} for language '{1}'" -f ($languagelist[$languageindex].InputMethodTips[$keyboardlayoutindex] -replace '.*:', ''), $languagelist[$languageindex].LanguageTag) | |
$languagelist[$languageindex].InputMethodTips.RemoveAt($keyboardlayoutindex) | |
$updateneeded = $true | |
} | |
} | |
} | |
if ($updateneeded) | |
{ | |
# make sure the first entry in the list hasn't changed | |
# as it seems Set-WinUserLanguageList sets the Windows UI display language to the first entry in the list | |
if ($languagelist[0].LanguageTag -ne $firstlanguage) | |
{ | |
$newlist = @() | |
$languagelist | Where-Object { $_.LanguageTag -eq $firstlanguage } | ForEach-Object { $newlist += $_ } | |
$languagelist | Where-Object { $_.LanguageTag -ne $firstlanguage } | ForEach-Object { $newlist += $_ } | |
$languagelist = $newlist | |
} | |
Set-WinUserLanguageList -LanguageList $languagelist -Force | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment