From 5bf1f635a6f4e36791aa0e8b5a9f4df80467abca Mon Sep 17 00:00:00 2001 From: rc-swag <58423624+rc-swag@users.noreply.github.com> Date: Tue, 15 Jul 2025 16:27:14 +1000 Subject: [PATCH] fix(windows): add check a fix for registry datatypes Fixes: #14342 The Windows system level keyboard hotkeys controlled in registry have sometimes been incorrectly written as a DWORD datatype. There 106 events in sentry for just July. When opening the Windows setting dialog and the registry has DWORDS it will show unassinged in the dialog if apply is pressed it will convert the keys to REG_SZ. This fix follows a similar pattern it will check the data type of the registry key if it is DWORD it will remove it and add a new key of the same name as REG_SZ and set it to the unassigned value. Fixes: KEYMAN-WINDOWS-4NK --- .../keyman/langswitch/LangSwitchManager.pas | 93 ++++++++++++++----- 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/windows/src/engine/keyman/langswitch/LangSwitchManager.pas b/windows/src/engine/keyman/langswitch/LangSwitchManager.pas index 80da078728..0a375695e0 100644 --- a/windows/src/engine/keyman/langswitch/LangSwitchManager.pas +++ b/windows/src/engine/keyman/langswitch/LangSwitchManager.pas @@ -1,4 +1,4 @@ -(* +(* Name: LangSwitchManager Copyright: Copyright (C) SIL International. Documentation: @@ -47,6 +47,7 @@ unit LangSwitchManager; interface uses + ErrorControlledRegistry, System.Classes, System.Contnrs, System.SysUtils, @@ -230,6 +231,7 @@ type FLanguageToggle: string; FLayoutToggle: string; procedure LoadCurrentHotkey; + function FixRegistryDataType(RegistryKey: TRegistryErrorControlled; const ValueName: string): Boolean; procedure DisableWindowsHotkey; procedure RestoreWindowsHotkey; public @@ -251,7 +253,6 @@ uses InterfaceHotkeys, kmint, LoadIndirectStringUnit, - ErrorControlledRegistry, Registry, RegistryKeys, UfrmKeyman7Main, @@ -981,38 +982,73 @@ begin FCurrentHotkey := FindHotkey(kmcom.Hotkeys); end; +function TLangSwitchConfiguration.FixRegistryDataType( + RegistryKey: TRegistryErrorControlled; + const ValueName: string +): Boolean; +var + RegType: TRegDataType; + const CHotkeyNotAssigned = '3'; +begin + Result := False; + + if RegistryKey.ValueExists(ValueName) then + begin + RegType := RegistryKey.GetDataType(ValueName); + if not ((RegType = rdString) or (RegType = rdExpandString)) then + begin + RegistryKey.DeleteValue(ValueName); + RegistryKey.WriteString(ValueName, CHotkeyNotAssigned); + Result := True; + end; + end; + +end; + procedure TLangSwitchConfiguration.DisableWindowsHotkey; var MatchValue: string; - FReset: Boolean; + KeyboardToggleReg: TRegistryErrorControlled; + FReset, FFixed: Boolean; + const CHotkeyNotAssigned = '3'; begin if FCurrentHotkey = (HK_ALT or HK_SHIFT) then MatchValue := '1' else if FCurrentHotkey = (HK_CTRL or HK_SHIFT) then MatchValue := '2' else Exit; - FLanguageToggle := '3'; - FLayoutToggle := '3'; + FLanguageToggle := CHotkeyNotAssigned; + FLayoutToggle := CHotkeyNotAssigned; + //FFixed := False; FReset := False; - with TRegistryErrorControlled.Create do // I2890 + KeyboardToggleReg := TRegistryErrorControlled.Create; // I2890 try - if not OpenKey(SRegKey_KeyboardLayoutToggle, True) then // I2890 - RaiseLastRegistryError; + if not KeyboardToggleReg.OpenKey(SRegKey_KeyboardLayoutToggle, True) then // I2890 + KeyboardToggleReg.RaiseLastRegistryError; + // Fix potential corrupted registry keys + if FixRegistryDataType(KeyboardToggleReg, SRegValue_Toggle_Hotkey) then + FReset := True; + if FixRegistryDataType(KeyboardToggleReg, SRegValue_Toggle_LanguageHotkey) then + FReset := True; + if FixRegistryDataType(KeyboardToggleReg, SRegValue_Toggle_LayoutHotkey) then + FReset := True; - if ValueExists(SRegValue_Toggle_Hotkey) then FLanguageToggle := ReadString(SRegValue_Toggle_Hotkey); + if KeyboardToggleReg.ValueExists(SRegValue_Toggle_Hotkey) then + FLanguageToggle := KeyboardToggleReg.ReadString(SRegValue_Toggle_Hotkey); if FLanguageToggle = MatchValue then begin - WriteString(SRegValue_Toggle_Hotkey, '3'); - WriteString(SRegValue_Toggle_LanguageHotkey, '3'); + KeyboardToggleReg.WriteString(SRegValue_Toggle_Hotkey, CHotkeyNotAssigned); + KeyboardToggleReg.WriteString(SRegValue_Toggle_LanguageHotkey, CHotkeyNotAssigned); FReset := True; end; - if ValueExists(SRegValue_Toggle_LayoutHotkey) then FLayoutToggle := ReadString(SRegValue_Toggle_LayoutHotkey); + if KeyboardToggleReg.ValueExists(SRegValue_Toggle_LayoutHotkey) then + FLayoutToggle := KeyboardToggleReg.ReadString(SRegValue_Toggle_LayoutHotkey); if FLayoutToggle = MatchValue then begin - WriteString(SRegValue_Toggle_LayoutHotkey, '3'); + KeyboardToggleReg.WriteString(SRegValue_Toggle_LayoutHotkey, CHotkeyNotAssigned); FReset := True; end; finally @@ -1024,31 +1060,42 @@ end; procedure TLangSwitchConfiguration.RestoreWindowsHotkey; var - FReset: Boolean; + FReset, Changed: Boolean; + KeyboardToggleReg: TRegistryErrorControlled; begin FReset := False; if FLanguageToggle = '' then Exit; - with TRegistryErrorControlled.Create do // I2890 + KeyboardToggleReg := TRegistryErrorControlled.Create; // I2890 try - if not OpenKey(SRegKey_KeyboardLayoutToggle, True) then // I2890 - RaiseLastRegistryError; + if not KeyboardToggleReg.OpenKey(SRegKey_KeyboardLayoutToggle, True) then // I2890 + KeyboardToggleReg.RaiseLastRegistryError; - if not ValueExists(SRegValue_Toggle_Hotkey) or (ReadString(SRegValue_Toggle_Hotkey) <> FLanguageToggle) then + // Fix potential corrupted registry keys + if FixRegistryDataType(KeyboardToggleReg, SRegValue_Toggle_Hotkey) then + FReset := True; + if FixRegistryDataType(KeyboardToggleReg, SRegValue_Toggle_LanguageHotkey) then + FReset := True; + if FixRegistryDataType(KeyboardToggleReg, SRegValue_Toggle_LayoutHotkey) then + FReset := True; + + if not KeyboardToggleReg.ValueExists(SRegValue_Toggle_Hotkey) or + (KeyboardToggleReg.ReadString(SRegValue_Toggle_Hotkey) <> FLanguageToggle) then begin - WriteString(SRegValue_Toggle_Hotkey, FLanguageToggle); - WriteString(SRegValue_Toggle_LanguageHotkey, FLanguageToggle); + KeyboardToggleReg.WriteString(SRegValue_Toggle_Hotkey, FLanguageToggle); + KeyboardToggleReg.WriteString(SRegValue_Toggle_LanguageHotkey, FLanguageToggle); FReset := True; end; - if not ValueExists(SRegValue_Toggle_LayoutHotkey) or (ReadString(SRegValue_Toggle_LayoutHotkey) <> FLayoutToggle) then + if not KeyboardToggleReg.ValueExists(SRegValue_Toggle_LayoutHotkey) or + (KeyboardToggleReg.ReadString(SRegValue_Toggle_LayoutHotkey) <> FLayoutToggle) then begin - WriteString(SRegValue_Toggle_LayoutHotkey, FLayoutToggle); + KeyboardToggleReg.WriteString(SRegValue_Toggle_LayoutHotkey, FLayoutToggle); FReset := True; end; finally - Free; + KeyboardToggleReg.Free; end; if FReset then