diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/TextCompositionManager.cs b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/TextCompositionManager.cs
index 5dd95d987c7..a23e839010a 100644
--- a/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/TextCompositionManager.cs
+++ b/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/TextCompositionManager.cs
@@ -1,23 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Text;
using System.Windows.Threading;
-using System.Runtime.InteropServices;
-using MS.Win32;
+using System.ComponentModel;
using Microsoft.Win32;
+using MS.Win32;
namespace System.Windows.Input
{
- //
- // Modes of AltNumpad.
- //
+ ///
+ /// Modes when entering characters via Alt+Numpad keys.
+ ///
internal enum AltNumpadConversionMode
{
- DefaultCodePage, // ACP code page encoding. Alt+Numpad0+NumpadX
- OEMCodePage, // OEM code page encoding. Alt+NumpadX
- HexDefaultCodePage, // HEX value in ACP. Alt+NumpadDOT+NumpadX
- HexUnicode, // HEX value in Unicode. Alt+NumpadPlus+NumpadX
+ ///
+ /// ACP code page encoding: Alt+Numpad0+NumpadX
+ ///
+ DefaultCodePage,
+ ///
+ /// OEM code page encoding: Alt+NumpadX
+ ///
+ OEMCodePage,
+ ///
+ /// HEX value in ACP: Alt+NumpadDOT+NumpadX
+ ///
+ HexDefaultCodePage,
+ ///
+ /// HEX value in Unicode: Alt+NumpadPlus+NumpadX
+ ///
+ HexUnicode,
}
///
@@ -374,31 +385,33 @@ private static bool UnsafeCompleteComposition(TextComposition composition)
private static string GetCurrentOEMCPEncoding(int code)
{
- int cp = UnsafeNativeMethods.GetOEMCP();
- return CharacterEncoding(cp, code);
- }
-
- // Convert code to the string based on the code page.
- private static string CharacterEncoding(int cp, int code)
- {
- Byte[] bytes = ConvertCodeToByteArray(code);
- StringBuilder sbuilder = new StringBuilder(EncodingBufferLen);
+ int codePage = UnsafeNativeMethods.GetOEMCP();
- // Win32K uses MB_PRECOMPOSED | MB_USEGLYPHCHARS.
- int nret = UnsafeNativeMethods.MultiByteToWideChar(cp,
- UnsafeNativeMethods.MB_PRECOMPOSED | UnsafeNativeMethods.MB_USEGLYPHCHARS,
- bytes, bytes.Length,
- sbuilder, EncodingBufferLen);
+ return CharacterEncoding(codePage, code);
+ }
- if (nret == 0)
- {
- int win32Err = Marshal.GetLastWin32Error();
- throw new System.ComponentModel.Win32Exception(win32Err);
+ ///
+ /// Convert to a string based on the .
+ ///
+ private static unsafe string CharacterEncoding(int codePage, int code)
+ {
+ ReadOnlySpan multiByte = ConvertCodeToByteArray(code, stackalloc byte[2]);
+ Span outputChars = stackalloc char[EncodingBufferLen]; // 4
+
+ int charsWritten;
+ // Since we do not use [LibraryImport], Span marshallers are not available by default
+ fixed (byte* ptrMultiByte = multiByte)
+ fixed (char* ptrOutputChars = outputChars)
+ { // Win32K uses MB_PRECOMPOSED | MB_USEGLYPHCHARS.
+ charsWritten = UnsafeNativeMethods.MultiByteToWideChar(codePage, UnsafeNativeMethods.MB_PRECOMPOSED | UnsafeNativeMethods.MB_USEGLYPHCHARS,
+ ptrMultiByte, multiByte.Length, ptrOutputChars, outputChars.Length);
}
- // set the length as MultiByteToWideChar returns.
- sbuilder.Length = nret;
- return sbuilder.ToString();
+ if (charsWritten == 0)
+ throw new Win32Exception(); // Initializes with Marshal.GetLastPInvokeError()
+
+ // Set the length as MultiByteToWideChar returns
+ return new string(outputChars.Slice(0, charsWritten));
}
// PreProcessInput event handler
@@ -470,40 +483,37 @@ private void PreProcessInput(object sender, PreProcessInputEventArgs e)
private void PostProcessInput(object sender, ProcessInputEventArgs e)
{
// KeyUp
- if(e.StagingItem.Input.RoutedEvent == Keyboard.KeyUpEvent)
+ if (e.StagingItem.Input.RoutedEvent == Keyboard.KeyUpEvent)
{
- KeyEventArgs keyArgs = (KeyEventArgs) e.StagingItem.Input;
- if(!keyArgs.Handled)
+ KeyEventArgs keyArgs = (KeyEventArgs)e.StagingItem.Input;
+ if (!keyArgs.Handled)
{
- if(keyArgs.RealKey == Key.LeftAlt || keyArgs.RealKey == Key.RightAlt)
+ if (keyArgs.RealKey is Key.LeftAlt or Key.RightAlt)
{
// Make sure both Alt keys are up.
ModifierKeys modifiers = keyArgs.KeyboardDevice.Modifiers;
- if((modifiers & ModifierKeys.Alt) == 0)
+ if ((modifiers & ModifierKeys.Alt) == 0)
{
- if(_altNumpadEntryMode)
+ if (_altNumpadEntryMode)
{
_altNumpadEntryMode = false;
// Generate the Unicode equivalent if we
// actually entered a number via the numpad.
- if(_altNumpadEntry != 0)
+ if (_altNumpadEntry != 0)
{
_altNumpadcomposition.ClearTexts();
- if (_altNumpadConversionMode == AltNumpadConversionMode.OEMCodePage)
+ if (_altNumpadConversionMode is AltNumpadConversionMode.OEMCodePage)
{
_altNumpadcomposition.SetText(GetCurrentOEMCPEncoding(_altNumpadEntry));
}
- else if ((_altNumpadConversionMode == AltNumpadConversionMode.DefaultCodePage) ||
- (_altNumpadConversionMode == AltNumpadConversionMode.HexDefaultCodePage))
+ else if (_altNumpadConversionMode is AltNumpadConversionMode.DefaultCodePage or AltNumpadConversionMode.HexDefaultCodePage)
{
_altNumpadcomposition.SetText(CharacterEncoding(InputLanguageManager.Current.CurrentInputLanguage.TextInfo.ANSICodePage, _altNumpadEntry));
}
- else if (_altNumpadConversionMode == AltNumpadConversionMode.HexUnicode)
+ else if (_altNumpadConversionMode is AltNumpadConversionMode.HexUnicode)
{
- Char[] chars = new Char[1];
- chars[0] = (Char) _altNumpadEntry;
- _altNumpadcomposition.SetText(new string(chars));
+ _altNumpadcomposition.SetText(((char)_altNumpadEntry).ToString());
}
}
}
@@ -839,22 +849,25 @@ private int GetNewEntry(Key key, int scanCode)
return NumpadScanCode.DigitFromScanCode(scanCode);
}
- // Convert the code to byte array for DBCS/SBCS.
- private static Byte[] ConvertCodeToByteArray(int codeEntry)
+ ///
+ /// Convert the code to byte array for DBCS/SBCS.
+ ///
+ private static ReadOnlySpan ConvertCodeToByteArray(int codeEntry, Span destination)
{
- Byte[] bytes;
- if (codeEntry > 0xff)
+ Debug.Assert(destination.Length == 2, "Invalid buffer length");
+
+ if (codeEntry > 0xFF)
{
- bytes = new Byte[2];
- bytes[0] = (Byte)(codeEntry >> 8);
- bytes[1] = (Byte)codeEntry;
+ destination[0] = (byte)(codeEntry >> 8);
+ destination[1] = (byte)codeEntry;
}
else
{
- bytes = new Byte[1];
- bytes[0] = (Byte)codeEntry;
+ destination = destination.Slice(0, 1);
+ destination[0] = (byte)codeEntry;
}
- return bytes;
+
+ return destination;
}
// clear the altnumpad composition object and reset entry.
@@ -875,13 +888,7 @@ private void ClearAltnumpadComposition()
// Return true if we're in hex conversion mode.
private bool HexConversionMode
{
- get
- {
- if ((_altNumpadConversionMode == AltNumpadConversionMode.HexDefaultCodePage) ||
- (_altNumpadConversionMode == AltNumpadConversionMode.HexUnicode))
- return true;
- return false;
- }
+ get => _altNumpadConversionMode is AltNumpadConversionMode.HexDefaultCodePage or AltNumpadConversionMode.HexUnicode;
}
///
@@ -893,15 +900,11 @@ private static bool IsHexNumpadEnabled
{
if (!_isHexNumpadRegistryChecked)
{
- object obj;
- RegistryKey key;
-
- key = Registry.CurrentUser.OpenSubKey("Control Panel\\Input Method");
+ RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel\\Input Method");
if (key != null)
{
- obj = key.GetValue("EnableHexNumpad");
-
- if ((obj is string) && ((string)obj != "0"))
+ object obj = key.GetValue("EnableHexNumpad");
+ if (obj is string value && value != "0")
{
_isHexNumpadEnabled = true;
}
@@ -909,6 +912,7 @@ private static bool IsHexNumpadEnabled
_isHexNumpadRegistryChecked = true;
}
+
return _isHexNumpadEnabled;
}
}
@@ -951,23 +955,21 @@ private static bool IsHexNumpadEnabled
// ScanCode of Numpad keys.
internal static class NumpadScanCode
{
- internal static int DigitFromScanCode(int scanCode)
- {
- switch (scanCode)
- {
- case Numpad0: return 0;
- case Numpad1: return 1;
- case Numpad2: return 2;
- case Numpad3: return 3;
- case Numpad4: return 4;
- case Numpad5: return 5;
- case Numpad6: return 6;
- case Numpad7: return 7;
- case Numpad8: return 8;
- case Numpad9: return 9;
- }
- return -1;
- }
+ internal static int DigitFromScanCode(int scanCode) => scanCode switch
+ {
+ Numpad0 => 0,
+ Numpad1 => 1,
+ Numpad2 => 2,
+ Numpad3 => 3,
+ Numpad4 => 4,
+ Numpad5 => 5,
+ Numpad6 => 6,
+ Numpad7 => 7,
+ Numpad8 => 8,
+ Numpad9 => 9,
+ _ => -1,
+ };
+
internal const int NumpadDot = 0x53;
internal const int NumpadPlus = 0x4e;
internal const int Numpad0 = 0x52;
diff --git a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/UnsafeNativeMethodsCLR.cs b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/UnsafeNativeMethodsCLR.cs
index aa055401be8..febda4e81ed 100644
--- a/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/UnsafeNativeMethodsCLR.cs
+++ b/src/Microsoft.DotNet.Wpf/src/Shared/MS/Win32/UnsafeNativeMethodsCLR.cs
@@ -213,7 +213,7 @@ internal enum ShellExecuteFlags
public const int MB_USEGLYPHCHARS = 0x00000004;
public const int MB_ERR_INVALID_CHARS = 0x00000008;
[DllImport(ExternDll.Kernel32, ExactSpelling=true, CharSet=CharSet.Unicode, SetLastError=true)]
- public static extern int MultiByteToWideChar(int CodePage, int dwFlags, byte[] lpMultiByteStr, int cchMultiByte, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpWideCharStr, int cchWideChar);
+ public static unsafe extern int MultiByteToWideChar(int CodePage, int dwFlags, byte* lpMultiByteStr, int cchMultiByte, char* lpWideCharStr, int cchWideChar);
[DllImport(ExternDll.Kernel32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
public static extern int WideCharToMultiByte(int codePage, int flags, [MarshalAs(UnmanagedType.LPWStr)]string wideStr, int chars, [In,Out]byte[] pOutBytes, int bufferBytes, IntPtr defaultChar, IntPtr pDefaultUsed);