|
1 | 1 | |
| 2 | +using IWshRuntimeLibrary; |
| 3 | +using PInvoke; |
| 4 | +using System; |
2 | 5 | using System.Collections; |
3 | 6 | using System.ComponentModel.Design; |
4 | 7 | using System.Diagnostics; |
|
11 | 14 | using System.Windows; |
12 | 15 | using System.Windows.Controls.Primitives; |
13 | 16 | using System.Windows.Media; |
14 | | - |
15 | | -using IWshRuntimeLibrary; |
16 | | -using PInvoke; |
17 | | - |
18 | 17 | using Point = System.Windows.Point; |
19 | 18 |
|
20 | 19 | namespace MarvinsAIRARefactored.Classes; |
@@ -253,33 +252,154 @@ public static void MoveCursorToElement( FrameworkElement element ) |
253 | 252 | User32.SetCursorPos( (int) Math.Round( p.X ), (int) Math.Round( p.Y ) ); |
254 | 253 | } |
255 | 254 |
|
256 | | - private static readonly Encoding Latin1Encoding = Encoding.GetEncoding( "iso-8859-1", new EncoderReplacementFallback( "?" ), new DecoderReplacementFallback( "?" ) ); |
257 | | - |
258 | | - public static string ToBestEffortLatin1( string input ) |
| 255 | + private static readonly Dictionary<char, string> IracingChatMap = new() |
| 256 | + { |
| 257 | + // German (and friends) |
| 258 | + [ 'Ä' ] = "Ae", |
| 259 | + [ 'Ö' ] = "Oe", |
| 260 | + [ 'Ü' ] = "Ue", |
| 261 | + [ 'ä' ] = "ae", |
| 262 | + [ 'ö' ] = "oe", |
| 263 | + [ 'ü' ] = "ue", |
| 264 | + [ 'ß' ] = "ss", |
| 265 | + |
| 266 | + // Turkish |
| 267 | + [ 'İ' ] = "I", |
| 268 | + [ 'ı' ] = "i", |
| 269 | + [ 'Ş' ] = "S", |
| 270 | + [ 'ş' ] = "s", |
| 271 | + [ 'Ğ' ] = "G", |
| 272 | + [ 'ğ' ] = "g", |
| 273 | + |
| 274 | + // Romanian (comma-below forms) |
| 275 | + [ 'Ș' ] = "S", |
| 276 | + [ 'ș' ] = "s", |
| 277 | + [ 'Ț' ] = "T", |
| 278 | + [ 'ț' ] = "t", |
| 279 | + |
| 280 | + // Polish |
| 281 | + [ 'Ł' ] = "L", |
| 282 | + [ 'ł' ] = "l", |
| 283 | + [ 'Ą' ] = "A", |
| 284 | + [ 'ą' ] = "a", |
| 285 | + [ 'Ę' ] = "E", |
| 286 | + [ 'ę' ] = "e", |
| 287 | + [ 'Ń' ] = "N", |
| 288 | + [ 'ń' ] = "n", |
| 289 | + [ 'Ś' ] = "S", |
| 290 | + [ 'ś' ] = "s", |
| 291 | + [ 'Ź' ] = "Z", |
| 292 | + [ 'ź' ] = "z", |
| 293 | + [ 'Ż' ] = "Z", |
| 294 | + [ 'ż' ] = "z", |
| 295 | + [ 'Ć' ] = "C", |
| 296 | + [ 'ć' ] = "c", |
| 297 | + [ 'Ó' ] = "O", |
| 298 | + [ 'ó' ] = "o", |
| 299 | + |
| 300 | + // Czech |
| 301 | + [ 'Č' ] = "C", |
| 302 | + [ 'č' ] = "c", |
| 303 | + [ 'Ď' ] = "D", |
| 304 | + [ 'ď' ] = "d", |
| 305 | + [ 'Ě' ] = "E", |
| 306 | + [ 'ě' ] = "e", |
| 307 | + [ 'Ň' ] = "N", |
| 308 | + [ 'ň' ] = "n", |
| 309 | + [ 'Ř' ] = "R", |
| 310 | + [ 'ř' ] = "r", |
| 311 | + [ 'Š' ] = "S", |
| 312 | + [ 'š' ] = "s", |
| 313 | + [ 'Ť' ] = "T", |
| 314 | + [ 'ť' ] = "t", |
| 315 | + [ 'Ů' ] = "U", |
| 316 | + [ 'ů' ] = "u", |
| 317 | + [ 'Ž' ] = "Z", |
| 318 | + [ 'ž' ] = "z", |
| 319 | + |
| 320 | + // Hungarian |
| 321 | + [ 'Ő' ] = "O", |
| 322 | + [ 'ő' ] = "o", |
| 323 | + [ 'Ű' ] = "U", |
| 324 | + [ 'ű' ] = "u", |
| 325 | + }; |
| 326 | + |
| 327 | + private static bool IsLatin1( char ch ) => ch <= '\u00FF'; |
| 328 | + |
| 329 | + public static string ToIracingChatSafeText( string input ) |
259 | 330 | { |
260 | | - // 1) Decompose accented letters into base letter + combining marks |
261 | | - var normalized = input.Normalize( NormalizationForm.FormD ); |
| 331 | + if ( string.IsNullOrEmpty( input ) ) |
| 332 | + { |
| 333 | + return input; |
| 334 | + } |
262 | 335 |
|
263 | | - // 2) Remove combining marks (diacritics) |
264 | | - var stringBuilder = new StringBuilder( normalized.Length ); |
| 336 | + var output = new StringBuilder( input.Length ); |
265 | 337 |
|
266 | | - foreach ( var ch in normalized ) |
| 338 | + foreach ( var ch in input ) |
267 | 339 | { |
268 | | - var category = CharUnicodeInfo.GetUnicodeCategory( ch ); |
| 340 | + // Try language-aware mapping first (Ł->L, Ş->S, etc.) |
269 | 341 |
|
270 | | - if ( ( category != UnicodeCategory.NonSpacingMark ) && ( category != UnicodeCategory.SpacingCombiningMark ) && ( category != UnicodeCategory.EnclosingMark ) ) |
| 342 | + if ( IracingChatMap.TryGetValue( ch, out var mapped ) ) |
271 | 343 | { |
272 | | - stringBuilder.Append( ch ); |
| 344 | + output.Append( mapped ); |
| 345 | + |
| 346 | + continue; |
| 347 | + } |
| 348 | + |
| 349 | + // Keep true Latin-1 as-is (ä stays ä) |
| 350 | + |
| 351 | + if ( IsLatin1( ch ) ) |
| 352 | + { |
| 353 | + output.Append( ch ); |
| 354 | + |
| 355 | + continue; |
273 | 356 | } |
| 357 | + |
| 358 | + // Try diacritic stripping for remaining Latin letters |
| 359 | + |
| 360 | + var stripped = StripDiacritics( ch.ToString() ); |
| 361 | + |
| 362 | + var appendedAnything = false; |
| 363 | + |
| 364 | + foreach ( var strippedChar in stripped ) |
| 365 | + { |
| 366 | + if ( IsLatin1( strippedChar ) ) |
| 367 | + { |
| 368 | + output.Append( strippedChar ); |
| 369 | + |
| 370 | + appendedAnything = true; |
| 371 | + } |
| 372 | + } |
| 373 | + |
| 374 | + if ( appendedAnything ) |
| 375 | + { |
| 376 | + continue; |
| 377 | + } |
| 378 | + |
| 379 | + // Non-Latin scripts (ru-RU, hy-AM, ja-JP, zh-Hans) -> no good in iRacing chat |
| 380 | + |
| 381 | + output.Append( '?' ); |
274 | 382 | } |
275 | 383 |
|
276 | | - // 3) Re-compose (optional but tidy) |
277 | | - var noDiacritics = stringBuilder.ToString().Normalize( NormalizationForm.FormC ); |
| 384 | + return output.ToString(); |
| 385 | + } |
| 386 | + |
| 387 | + private static string StripDiacritics( string value ) |
| 388 | + { |
| 389 | + var normalized = value.Normalize( NormalizationForm.FormD ); |
| 390 | + |
| 391 | + var stringBuilder = new StringBuilder( normalized.Length ); |
278 | 392 |
|
279 | | - // 4) Encode to Latin-1 with '?' replacement for anything still unsupported |
280 | | - var bytes = Latin1Encoding.GetBytes( noDiacritics ); |
| 393 | + foreach ( var c in normalized ) |
| 394 | + { |
| 395 | + var category = CharUnicodeInfo.GetUnicodeCategory( c ); |
| 396 | + |
| 397 | + if ( category != UnicodeCategory.NonSpacingMark && category != UnicodeCategory.SpacingCombiningMark && category != UnicodeCategory.EnclosingMark ) |
| 398 | + { |
| 399 | + stringBuilder.Append( c ); |
| 400 | + } |
| 401 | + } |
281 | 402 |
|
282 | | - // 5) Convert back to a .NET string that contains only U+0000..U+00FF chars |
283 | | - return Latin1Encoding.GetString( bytes ); |
| 403 | + return stringBuilder.ToString().Normalize( NormalizationForm.FormC ); |
284 | 404 | } |
285 | 405 | } |
0 commit comments