1using System; 2using System.Collections.Generic; 3using System.Drawing; 4using System.IO; 5using WindowCapture.Helpers; 6 7namespace WindowCapture.Models 8{ 9 public static class Settings 10 { 11 static string settingsPath = Path.Combine( 12 AppDomain.CurrentDomain.BaseDirectory, "settings.ini"); 13 14 // Arrow settings 15 public static Color ArrowColor = Color.FromArgb(255, 220, 60, 60); 16 public static float ArrowWidth = 3f; 17 public static int ShadowOffset = 3; 18 public static int ShadowAlpha = 100; 19 20 // Marker settings 21 public static Color MarkerColor = Color.FromArgb(230, 220, 60, 60); 22 public static Color MarkerTextColor = Color.White; 23 public static int MarkerRadius = 16; 24 public static string MarkerFont = "Segoe UI"; 25 public static float MarkerFontSize = 12f; 26 27 // Highlight settings 28 public static Color HighlightColor = Color.FromArgb(255, 255, 255, 0); 29 public static int HighlightAlpha = 60; 30 public static Color HighlightBorderColor = Color.FromArgb(255, 255, 100, 100); 31 public static float HighlightBorderWidth = 2f; 32 public static int DimAlpha = 120; 33 public static bool ShowHighlightBorder = true; 34 // When true, drawing a highlight automatically dims everything around it (spotlight focus). 35 public static bool DimAroundSelection = true; 36 37 // Marker settings (extended) 38 public static int MarkerSize = 32; 39 public static Color MarkerBorderColor = Color.FromArgb(255, 180, 40, 40); 40 41 // Text block settings 42 public static string TextBlockFont = "Segoe UI"; 43 public static float TextBlockFontSize = 14f; 44 public static Color TextBlockColor = Color.White; 45 public static Color TextBlockShadowColor = Color.FromArgb(150, 0, 0, 0); 46 public static int TextBlockShadowOffset = 2; 47 48 // Comment bubble settings 49 public static string BubbleFont = "Segoe UI"; 50 public static float BubbleFontSize = 12f; 51 public static Color BubbleFillColor = Color.White; 52 public static Color BubbleBorderColor = Color.Black; 53 public static int BubbleBorderWidth = 2; 54 55 // Blur settings 56 public static float BlurRadius = 1.0f; // Base blur radius (will be scaled by resolution) 57 public static int MotionBlurDistance = 15; 58 public static int ReferenceResolution = 1920; // Reference width for blur scaling 59 public static int FeatherWidth = 5; 60 public static bool EnableFadeBlur = false; 61 public static int FadeBlurWidth = 20; 62 63 // Window settings 64 public static int DefaultWindowWidth = 1200; 65 public static int DefaultWindowHeight = 800; 66 public static bool AutoFitToWindow = true; 67 68 // Window appearance 69 public static int BlurTintAlpha = 232; // 0xE8 70 public static Color BlurTintColor = Color.FromArgb(255, 24, 20, 20); 71 public static int BlurMode = 0; // 0=BlurBehind (less blur), 1=Acrylic (more blur) 72 public static int CornerRadius = 12; 73 public static bool ShowWindowBorder = true; 74 public static int NoiseIntensity = 12; // 0=none, 1-30 grain alpha 75 76 // Activation key (virtual key code) 77 // Default is Alt (VK_MENU = 0x12, VK_LMENU = 0xA4, VK_RMENU = 0xA5) 78 public static int ActivationKey = 0xA4; // Left Alt by default 79 public static string ActivationKeyName = "Alt"; 80 81 // Video recording settings 82 public static int VideoFps = 60; 83 public static int VideoJpegQuality = 90; 84 public static bool RecordSystemAudio = true; 85 public static bool RecordMicrophone = false; 86 87 // Audio player window size 88 public static int AudioPlayerW = 440; 89 public static float AudioVolume = 0.85f; 90 91 // Text processing: auto language switch + T9 92 public static bool AutoLangSwitch = true; 93 public static bool AutoT9 = true; 94 public static int T9Sensitivity = 3; // 1-5 95 public static bool T9ShowTooltip = true; 96 public static bool AutoCapitalize = true; 97 public static bool AutoPunctuation = true; 98 public static bool ClipboardHistory = true; 99 // Live SAGE full-sentence suggestion on sentence end (non-destructive tooltip). Off by default. 100 public static bool SentenceAiSuggest = false; 101 // Auto-apply the SAGE sentence correction in place (backspace+type at caret). Experimental, off. 102 public static bool SentenceAiAutoApply = false; 103 // Per-word context neural rescore (rubert-tiny2 stage-2 of the pipeline). Experimental, off. 104 public static bool ContextNnRescore = false; 105 // Localhost bridge for the native TSF TIP (universal in-place edit, Tip/WCTip.cpp). Experimental, off. 106 public static bool TsfBridge = false; 107 108 // ===== Unified MediaCore app: which modules are active (toggled live from the tray menu) ===== 109 // Only Screenshot defaults ON (benign Alt+Win hotkey). The modules that inject keystrokes or 110 // hook the mouse — autocorrect, clipboard Ctrl+V intercept, gestures — are OPT-IN so a fresh 111 // launch never touches the user's typing or mouse until they knowingly enable it. 112 public static bool ModuleScreenshot = true; 113 public static bool ModuleTextAssist = false; 114 public static bool ModuleClipboard = false; 115 public static bool ModuleGestures = false; 116 117 public static void Load() 118 { 119 try 120 { 121 if (!File.Exists(settingsPath)) return; 122 foreach (var line in File.ReadAllLines(settingsPath)) 123 { 124 // Split on the first '=' only, so values containing '=' are preserved. 125 int eq = line.IndexOf('='); 126 if (eq < 0) continue; 127 var key = line.Substring(0, eq).Trim(); 128 var val = line.Substring(eq + 1).Trim(); 129 130 // Per-line guard: a single malformed value must not abort the whole load. 131 try 132 { 133 switch (key) 134 { 135 case "ArrowColor": ArrowColor = ColorFromHex(val); break; 136 case "ArrowWidth": ArrowWidth = float.Parse(val, System.Globalization.CultureInfo.InvariantCulture); break; 137 case "ShadowOffset": ShadowOffset = int.Parse(val); break; 138 case "ShadowAlpha": ShadowAlpha = int.Parse(val); break; 139 case "MarkerColor": MarkerColor = ColorFromHex(val); break; 140 case "MarkerTextColor": MarkerTextColor = ColorFromHex(val); break; 141 case "MarkerRadius": MarkerRadius = int.Parse(val); break; 142 case "MarkerFont": MarkerFont = val; break; 143 case "MarkerFontSize": MarkerFontSize = float.Parse(val, System.Globalization.CultureInfo.InvariantCulture); break; 144 case "HighlightBorderColor": HighlightBorderColor = ColorFromHex(val); break; 145 case "HighlightBorderWidth": HighlightBorderWidth = float.Parse(val, System.Globalization.CultureInfo.InvariantCulture); break; 146 case "DimAlpha": DimAlpha = int.Parse(val); break; 147 case "ShowHighlightBorder": ShowHighlightBorder = val == "1" || val.ToLower() == "true"; break; 148 case "DimAroundSelection": DimAroundSelection = val == "1" || val.ToLower() == "true"; break; 149 case "TextBlockFont": TextBlockFont = val; break; 150 case "TextBlockFontSize": TextBlockFontSize = float.Parse(val, System.Globalization.CultureInfo.InvariantCulture); break; 151 case "TextBlockColor": TextBlockColor = ColorFromHex(val); break; 152 case "TextBlockShadowColor": TextBlockShadowColor = ColorFromHex(val); break; 153 case "TextBlockShadowOffset": TextBlockShadowOffset = int.Parse(val); break; 154 case "BubbleFont": BubbleFont = val; break; 155 case "BubbleFontSize": BubbleFontSize = float.Parse(val, System.Globalization.CultureInfo.InvariantCulture); break; 156 case "BubbleFillColor": BubbleFillColor = ColorFromHex(val); break; 157 case "BubbleBorderColor": BubbleBorderColor = ColorFromHex(val); break; 158 case "BubbleBorderWidth": BubbleBorderWidth = int.Parse(val); break; 159 case "BlurRadius": BlurRadius = float.Parse(val, System.Globalization.CultureInfo.InvariantCulture); break; 160 case "MotionBlurDistance": MotionBlurDistance = int.Parse(val); break; 161 case "FeatherWidth": FeatherWidth = int.Parse(val); break; 162 case "EnableFadeBlur": EnableFadeBlur = val == "1" || val.ToLower() == "true"; break; 163 case "FadeBlurWidth": FadeBlurWidth = int.Parse(val); break; 164 case "DefaultWindowWidth": DefaultWindowWidth = int.Parse(val); break; 165 case "DefaultWindowHeight": DefaultWindowHeight = int.Parse(val); break; 166 case "AutoFitToWindow": AutoFitToWindow = val == "1" || val.ToLower() == "true"; break; 167 case "BlurTintAlpha": BlurTintAlpha = int.Parse(val); break; 168 case "BlurTintColor": BlurTintColor = ColorFromHex(val); break; 169 case "BlurMode": BlurMode = int.Parse(val); break; 170 case "CornerRadius": CornerRadius = int.Parse(val); break; 171 case "ShowWindowBorder": ShowWindowBorder = val == "1" || val.ToLower() == "true"; break; 172 case "NoiseIntensity": NoiseIntensity = Math.Max(0, Math.Min(30, int.Parse(val))); break; 173 case "ActivationKey": ActivationKey = int.Parse(val); break; 174 case "ActivationKeyName": ActivationKeyName = val; break; 175 case "VideoFps": VideoFps = Math.Max(1, Math.Min(120, int.Parse(val))); break; 176 case "VideoJpegQuality": VideoJpegQuality = Math.Max(10, Math.Min(100, int.Parse(val))); break; 177 case "RecordSystemAudio": RecordSystemAudio = val == "1" || val.ToLower() == "true"; break; 178 case "RecordMicrophone": RecordMicrophone = val == "1" || val.ToLower() == "true"; break; 179 case "AudioPlayerW": AudioPlayerW = int.Parse(val); break; 180 case "AudioVolume": AudioVolume = float.Parse(val, System.Globalization.CultureInfo.InvariantCulture); break; 181 case "AutoLangSwitch": AutoLangSwitch = val == "1" || val.ToLower() == "true"; break; 182 case "AutoT9": AutoT9 = val == "1" || val.ToLower() == "true"; break; 183 case "T9Sensitivity": T9Sensitivity = Math.Max(1, Math.Min(5, int.Parse(val))); break; 184 case "T9ShowTooltip": T9ShowTooltip = val == "1" || val.ToLower() == "true"; break; 185 case "AutoCapitalize": AutoCapitalize = val == "1" || val.ToLower() == "true"; break; 186 case "AutoPunctuation": AutoPunctuation = val == "1" || val.ToLower() == "true"; break; 187 case "ClipboardHistory": ClipboardHistory = val == "1" || val.ToLower() == "true"; break; 188 case "SentenceAiSuggest": SentenceAiSuggest = val == "1" || val.ToLower() == "true"; break; 189 case "SentenceAiAutoApply": SentenceAiAutoApply = val == "1" || val.ToLower() == "true"; break; 190 case "ContextNnRescore": ContextNnRescore = val == "1" || val.ToLower() == "true"; break; 191 case "TsfBridge": TsfBridge = val == "1" || val.ToLower() == "true"; break; 192 case "ModuleScreenshot": ModuleScreenshot = val == "1" || val.ToLower() == "true"; break; 193 case "ModuleTextAssist": ModuleTextAssist = val == "1" || val.ToLower() == "true"; break; 194 case "ModuleClipboard": ModuleClipboard = val == "1" || val.ToLower() == "true"; break; 195 case "ModuleGestures": ModuleGestures = val == "1" || val.ToLower() == "true"; break; 196 // Previously missing from Load() — these silently reverted to defaults on every restart. 197 case "HighlightColor": HighlightColor = ColorFromHex(val); break; 198 case "HighlightAlpha": HighlightAlpha = Math.Max(0, Math.Min(255, int.Parse(val))); break; 199 case "MarkerSize": MarkerSize = int.Parse(val); break; 200 case "MarkerBorderColor": MarkerBorderColor = ColorFromHex(val); break; 201 case "ReferenceResolution": ReferenceResolution = int.Parse(val); break; 202 } 203 } 204 catch { /* skip this malformed line, keep loading the rest */ } 205 } 206 } 207 catch { } 208 } 209 210 public static void Save() 211 { 212 try 213 { 214 var dir = Path.GetDirectoryName(settingsPath); 215 if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); 216 217 var lines = new List<string> 218 { 219 "ArrowColor=" + ColorToHex(ArrowColor), 220 "ArrowWidth=" + ArrowWidth.ToString(System.Globalization.CultureInfo.InvariantCulture), 221 "ShadowOffset=" + ShadowOffset, 222 "ShadowAlpha=" + ShadowAlpha, 223 "MarkerColor=" + ColorToHex(MarkerColor), 224 "MarkerTextColor=" + ColorToHex(MarkerTextColor), 225 "MarkerRadius=" + MarkerRadius, 226 "MarkerFont=" + MarkerFont, 227 "MarkerFontSize=" + MarkerFontSize.ToString(System.Globalization.CultureInfo.InvariantCulture), 228 "HighlightBorderColor=" + ColorToHex(HighlightBorderColor), 229 "HighlightBorderWidth=" + HighlightBorderWidth.ToString(System.Globalization.CultureInfo.InvariantCulture), 230 "DimAlpha=" + DimAlpha, 231 "ShowHighlightBorder=" + (ShowHighlightBorder ? "1" : "0"), 232 "DimAroundSelection=" + (DimAroundSelection ? "1" : "0"), 233 "TextBlockFont=" + TextBlockFont, 234 "TextBlockFontSize=" + TextBlockFontSize.ToString(System.Globalization.CultureInfo.InvariantCulture), 235 "TextBlockColor=" + ColorToHex(TextBlockColor), 236 "TextBlockShadowColor=" + ColorToHex(TextBlockShadowColor), 237 "TextBlockShadowOffset=" + TextBlockShadowOffset, 238 "BubbleFont=" + BubbleFont, 239 "BubbleFontSize=" + BubbleFontSize.ToString(System.Globalization.CultureInfo.InvariantCulture), 240 "BubbleFillColor=" + ColorToHex(BubbleFillColor), 241 "BubbleBorderColor=" + ColorToHex(BubbleBorderColor), 242 "BubbleBorderWidth=" + BubbleBorderWidth, 243 "BlurRadius=" + BlurRadius.ToString(System.Globalization.CultureInfo.InvariantCulture), 244 "MotionBlurDistance=" + MotionBlurDistance, 245 "FeatherWidth=" + FeatherWidth, 246 "EnableFadeBlur=" + (EnableFadeBlur ? "1" : "0"), 247 "FadeBlurWidth=" + FadeBlurWidth, 248 "DefaultWindowWidth=" + DefaultWindowWidth, 249 "DefaultWindowHeight=" + DefaultWindowHeight, 250 "AutoFitToWindow=" + (AutoFitToWindow ? "1" : "0"), 251 "BlurTintAlpha=" + BlurTintAlpha, 252 "BlurTintColor=" + ColorToHex(BlurTintColor), 253 "BlurMode=" + BlurMode, 254 "CornerRadius=" + CornerRadius, 255 "ShowWindowBorder=" + (ShowWindowBorder ? "1" : "0"), 256 "NoiseIntensity=" + NoiseIntensity, 257 "ActivationKey=" + ActivationKey, 258 "ActivationKeyName=" + ActivationKeyName, 259 "VideoFps=" + VideoFps, 260 "VideoJpegQuality=" + VideoJpegQuality, 261 "RecordSystemAudio=" + (RecordSystemAudio ? "1" : "0"), 262 "RecordMicrophone=" + (RecordMicrophone ? "1" : "0"), 263 "AudioPlayerW=" + AudioPlayerW, 264 "AudioVolume=" + AudioVolume.ToString(System.Globalization.CultureInfo.InvariantCulture), 265 "AutoLangSwitch=" + (AutoLangSwitch ? "1" : "0"), 266 "AutoT9=" + (AutoT9 ? "1" : "0"), 267 "T9Sensitivity=" + T9Sensitivity, 268 "T9ShowTooltip=" + (T9ShowTooltip ? "1" : "0"), 269 "AutoCapitalize=" + (AutoCapitalize ? "1" : "0"), 270 "AutoPunctuation=" + (AutoPunctuation ? "1" : "0"), 271 "ClipboardHistory=" + (ClipboardHistory ? "1" : "0"), 272 "SentenceAiSuggest=" + (SentenceAiSuggest ? "1" : "0"), 273 "SentenceAiAutoApply=" + (SentenceAiAutoApply ? "1" : "0"), 274 "ContextNnRescore=" + (ContextNnRescore ? "1" : "0"), 275 "TsfBridge=" + (TsfBridge ? "1" : "0"), 276 "ModuleScreenshot=" + (ModuleScreenshot ? "1" : "0"), 277 "ModuleTextAssist=" + (ModuleTextAssist ? "1" : "0"), 278 "ModuleClipboard=" + (ModuleClipboard ? "1" : "0"), 279 "ModuleGestures=" + (ModuleGestures ? "1" : "0"), 280 "HighlightColor=" + ColorToHex(HighlightColor), 281 "HighlightAlpha=" + HighlightAlpha, 282 "MarkerSize=" + MarkerSize, 283 "MarkerBorderColor=" + ColorToHex(MarkerBorderColor), 284 "ReferenceResolution=" + ReferenceResolution 285 }; 286 File.WriteAllLines(settingsPath, lines); 287 } 288 catch { } 289 } 290 291 public static void ResetDefaults() 292 { 293 ArrowColor = Color.FromArgb(255, 220, 60, 60); 294 ArrowWidth = 3f; 295 ShadowOffset = 3; 296 ShadowAlpha = 100; 297 MarkerColor = Color.FromArgb(230, 220, 60, 60); 298 MarkerTextColor = Color.White; 299 MarkerRadius = 16; 300 MarkerFont = "Segoe UI"; 301 MarkerFontSize = 12f; 302 HighlightBorderColor = Color.FromArgb(255, 255, 100, 100); 303 HighlightBorderWidth = 2f; 304 DimAlpha = 120; 305 ShowHighlightBorder = true; 306 DimAroundSelection = true; 307 HighlightColor = Color.FromArgb(255, 255, 255, 0); 308 HighlightAlpha = 60; 309 MarkerSize = 32; 310 MarkerBorderColor = Color.FromArgb(255, 180, 40, 40); 311 TextBlockFont = "Segoe UI"; 312 TextBlockFontSize = 14f; 313 TextBlockColor = Color.White; 314 TextBlockShadowColor = Color.FromArgb(150, 0, 0, 0); 315 TextBlockShadowOffset = 2; 316 BubbleFont = "Segoe UI"; 317 BubbleFontSize = 12f; 318 BubbleFillColor = Color.White; 319 BubbleBorderColor = Color.Black; 320 BubbleBorderWidth = 2; 321 BlurRadius = 1.0f; 322 MotionBlurDistance = 15; 323 ReferenceResolution = 1920; 324 FeatherWidth = 5; 325 EnableFadeBlur = false; 326 FadeBlurWidth = 20; 327 DefaultWindowWidth = 1200; 328 DefaultWindowHeight = 800; 329 AutoFitToWindow = true; 330 BlurTintAlpha = 232; 331 BlurTintColor = Color.FromArgb(255, 24, 20, 20); 332 BlurMode = 0; 333 CornerRadius = 12; 334 ShowWindowBorder = true; 335 NoiseIntensity = 12; 336 ActivationKey = 0xA4; 337 ActivationKeyName = "Alt"; 338 VideoFps = 60; 339 VideoJpegQuality = 90; 340 RecordSystemAudio = true; 341 RecordMicrophone = false; 342 AudioPlayerW = 440; 343 AudioVolume = 0.85f; 344 AutoLangSwitch = true; 345 AutoT9 = true; 346 T9Sensitivity = 3; 347 T9ShowTooltip = true; 348 AutoCapitalize = true; 349 AutoPunctuation = true; 350 ClipboardHistory = true; 351 SentenceAiSuggest = false; 352 SentenceAiAutoApply = false; 353 ContextNnRescore = false; 354 TsfBridge = false; 355 ModuleScreenshot = true; 356 ModuleTextAssist = false; 357 ModuleClipboard = false; 358 ModuleGestures = false; 359 } 360 361 public static Color ColorFromHex(string hex) 362 { 363 if (string.IsNullOrEmpty(hex)) return Color.Black; 364 if (hex.StartsWith("#")) hex = hex.Substring(1); 365 // Only 6 (RGB) and 8 (ARGB) hex digit forms are supported; anything else is malformed. 366 if (hex.Length != 6 && hex.Length != 8) return Color.Black; 367 int a = 255, r, g, b; 368 if (hex.Length == 8) 369 { 370 a = Convert.ToInt32(hex.Substring(0, 2), 16); 371 r = Convert.ToInt32(hex.Substring(2, 2), 16); 372 g = Convert.ToInt32(hex.Substring(4, 2), 16); 373 b = Convert.ToInt32(hex.Substring(6, 2), 16); 374 } 375 else 376 { 377 r = Convert.ToInt32(hex.Substring(0, 2), 16); 378 g = Convert.ToInt32(hex.Substring(2, 2), 16); 379 b = Convert.ToInt32(hex.Substring(4, 2), 16); 380 } 381 return Color.FromArgb(a, r, g, b); 382 } 383 384 public static string ColorToHex(Color c) 385 { 386 return ColorHelper.ColorToHex(c); 387 } 388 } 389}