removed font and codepage handling code that is only applicable to Windows PowerShell

replaced LengthInBufferCells() method with Unicode adapted code from PSReadline
This commit is contained in:
Steve Lee
2017-10-12 10:17:13 -07:00
parent 856c2af3fe
commit 46cdd7ec13
2 changed files with 27 additions and 300 deletions
@@ -2608,109 +2608,6 @@ namespace Microsoft.PowerShell
#endregion Window
#if !CORECLR
#region Font Selection
/// <summary>
/// UpdateLocaleSpecificFont is a helper method used to update
/// the console font based on the locale.
/// The default font face used for Powershell Console is Lucida Console.
/// However certain locales dont support Lucida Console font. Hence for such
/// locales the console font is updated to Raster dynamically.
/// </summary>
internal static void UpdateLocaleSpecificFont()
{
// Default Powershell shortcut.lnk settings.
const string defaultFontFace = "Lucida Console";
// Default CJK locale shortcut.lnk settings.
// Font size is hard coded here to ensure we select a supported size.
// GDI does a poor job of selecting raster font size if the requested
// size is not supported.
const string CJKFontFace = "Terminal";
const int CJKFontFamily = 48;
const int CJKnFont = 6;
const int CJKFontWidth = 8;
const int CJKFontHeight = 12;
const int CKJFontWeight = 400;
uint currentLocaleCodePage = (uint)ConsoleControl.NativeMethods.GetConsoleCP();
ConsoleHandle handle = ConsoleControl.GetActiveScreenBufferHandle();
CONSOLE_FONT_INFO_EX fontInfo;
try
{
fontInfo = ConsoleControl.GetConsoleFontInfo(handle);
}
catch (Exception)
{
return;
}
bool isLucidaConsoleSupportedLocale = CodePageSupportsLucida(currentLocaleCodePage);
// The Raster font is updated for Japanese and Korean locales if the user has not manually
// altered the default settings. If the default settings are altered then the
// setting chosen by the user would be used.
if (!isLucidaConsoleSupportedLocale &&
fontInfo.FontFace.Equals(defaultFontFace, StringComparison.OrdinalIgnoreCase))
{
fontInfo.FontFace = CJKFontFace;
fontInfo.FontFamily = CJKFontFamily;
fontInfo.nFont = CJKnFont;
fontInfo.FontWidth = CJKFontWidth;
fontInfo.FontHeight = CJKFontHeight;
fontInfo.FontWeight = CKJFontWeight;
bool result = NativeMethods.SetCurrentConsoleFontEx(handle.DangerousGetHandle(), false, ref fontInfo);
if (result == false)
{
int err = Marshal.GetLastWin32Error();
HostException e = CreateHostException(err,
"SetConsoleFontInfo",
ErrorCategory.ResourceUnavailable,
ConsoleControlStrings.SetConsoleFontInfoExceptionTemplate);
throw e;
}
}
}
/// <summary>
/// Supported Lucida code pages obtained from Font group.
/// Contacts: alib, judysa, simonda
/// </summary>
private static HashSet<uint> LucidaSupportedCodePages = new HashSet<uint>()
{
1251, // Latin 1
1250, // Latin 2
1251, // Cyrillic
1253, // Greek
1254, // Turkish
869, // IBM Greek
866, // MS-DOS Russian
865, // MS-DOS Nordic
863, // MS-DOS Canadian French
861, // MS-DOS Icelandic
860, // MS-DOS Portuguese
857, // IBM Turkish
855, // IBM Cyrillic
852, // Latin 2
737, // Greek
850, // WE/Latin 1
437 // US
//936, // SimplifiedChinese - According to font team this is *not* supported.
//950 // TraditionalChinese - According to font team this is *not* supported.
};
private static bool CodePageSupportsLucida(uint currentLocaleCodePage)
{
return LucidaSupportedCodePages.Contains(currentLocaleCodePage);
}
#endregion
#endif
/// <summary>
///
/// Wrap Win32 WriteConsole
@@ -2821,49 +2718,6 @@ namespace Microsoft.PowerShell
#region Dealing with CJK
#if !UNIX
/// <summary>
/// From IsConsoleFullWidth in \windows\core\ntcon\server\dbcs.c
/// Gets the CharSet for a code page
/// </summary>
/// <param name="codePage"></param>
/// <returns>The CharSet corresponding to the codePage; defaults to OEM_CHARSET (255)</returns>
private static uint CodePageToCharSet(uint codePage)
{
const uint OEM_CHARSET = 255;
// Suppress the PreFAST warning about not using Marshal.GetLastWin32Error() to
// get the error code.
#pragma warning disable 56523
#if CORECLR // TranslateCharsetInfo exists in an extension API set 'ext-ms-win-gdi-font-l1-1-1.dll', which is not available in NanoServer.
return OEM_CHARSET;
#else
CHARSETINFO csi;
const DWORD TCI_SRCCODEPAGE = 2;
if (!NativeMethods.TranslateCharsetInfo((IntPtr)codePage, out csi, TCI_SRCCODEPAGE))
{
csi.ciCharset = OEM_CHARSET;
}
return csi.ciCharset;
#endif
}
// From \windows\core\ntcon\server\dbcs.c
private static bool IsAvailableFarEastCodePage(uint codePage)
{
uint charSet = CodePageToCharSet(codePage);
return IsAnyDBCSCharSet(charSet);
}
// From \windows\core\ntcon\server\dbcs.c
private static bool IsAnyDBCSCharSet(uint charSet)
{
const uint SHIFTJIS_CHARSET = 128;
const uint HANGUL_CHARSET = 129;
const uint CHINESEBIG5_CHARSET = 136;
const uint GB2312_CHARSET = 134;
return charSet == SHIFTJIS_CHARSET || charSet == HANGUL_CHARSET ||
charSet == CHINESEBIG5_CHARSET || charSet == GB2312_CHARSET;
}
/// <summary>
/// From IsConsoleFullWidth in \windows\core\ntcon\server\dbcs.c
/// Precondition: the current code page needs to be a Far East code page.
@@ -2944,103 +2798,9 @@ namespace Microsoft.PowerShell
/* Han Compatibility Ideographs */
return 2;
}
else
{
// GetTextMetrics / GetCharWidth32 exist in an extension API set 'ext-ms-win-gdi-font-l1-1-1.dll', which is not available in NanoServer.
#if !CORECLR
/* Unknown character: need to use GDI*/
if (hDC == (IntPtr)0)
{
hwnd = NativeMethods.GetConsoleWindow();
if ((IntPtr)0 == hwnd)
{
int err = Marshal.GetLastWin32Error();
//Don't throw exception so that output can continue
tracer.TraceError("Win32 Error 0x{0:X} occurred when getting the window handle to the console.",
err);
return 1;
}
hDC = NativeMethods.GetDC(hwnd);
if ((IntPtr)0 == hDC)
{
int err = Marshal.GetLastWin32Error();
//Don't throw exception so that output can continue
tracer.TraceError("Win32 Error 0x{0:X} occurred when getting the Device Context of the console window.",
err);
return 1;
}
}
bool result = true;
if (!istmInitialized)
{
result = NativeMethods.GetTextMetrics(hDC, out tm);
if (!result)
{
int err = Marshal.GetLastWin32Error();
//Don't throw exception so that output can continue
tracer.TraceError("Win32 Error 0x{0:X} occurred when getting the Text Metric of the console window's Device Context.",
err);
return 1;
}
istmInitialized = true;
}
int width;
result = NativeMethods.GetCharWidth32(hDC, (uint)c, (uint)c, out width);
if (!result)
{
int err = Marshal.GetLastWin32Error();
//Don't throw exception so that output can continue
tracer.TraceError("Win32 Error 0x{0:X} occurred when getting the width of a char.",
err);
return 1;
}
if (width >= tm.tmMaxCharWidth)
{
return 2;
}
#endif
}
tracer.WriteLine("failed to locate char {0}, return 1", (int)c);
return 1;
}
internal static int LengthInBufferCells(char c)
{
uint codePage = NativeMethods.GetConsoleOutputCP();
return LengthInBufferCells(c, codePage);
}
/// <summary>
/// From IsConsoleFullWidth in \windows\core\ntcon\server\dbcs.c
/// </summary>
/// <param name="c"></param>
/// <param name="codePage"></param>
/// <returns></returns>
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults",
MessageId = "Microsoft.PowerShell.ConsoleControl+NativeMethods.ReleaseDC(System.IntPtr,System.IntPtr)")]
private static int LengthInBufferCells(char c, uint codePage)
{
if (!IsAvailableFarEastCodePage(codePage))
{
return 1;
}
HWND hwnd = (HWND)0;
HDC hDC = (HDC)0;
bool istmInitialized = false;
TEXTMETRIC tm = new TEXTMETRIC(); ;
try
{
return LengthInBufferCellsFE(c, ref hwnd, ref hDC, ref istmInitialized, ref tm);
}
finally
{
if (hwnd != (IntPtr)0 && hDC != (IntPtr)0)
{
NativeMethods.ReleaseDC(hwnd, hDC);
}
}
}
#endif
// Return the length of a VT100 control sequence character in str starting
@@ -3108,38 +2868,7 @@ namespace Microsoft.PowerShell
}
}
#if UNIX
return str.Length - offset - escapeSequenceAdjustment;
#else
uint codePage = NativeMethods.GetConsoleOutputCP();
if (!IsAvailableFarEastCodePage(codePage))
{
return str.Length - offset - escapeSequenceAdjustment;
}
HWND hwnd = (HWND)0;
HDC hDC = (HDC)0;
bool istmInitialized = false;
TEXTMETRIC tm = new TEXTMETRIC(); ;
int length = 0;
try
{
int n = str.Length;
for (int i = offset; i < n; i++)
{
char c = str[i];
length += LengthInBufferCellsFE(c, ref hwnd, ref hDC, ref istmInitialized, ref tm);
}
return length - escapeSequenceAdjustment;
}
finally
{
if (hwnd != (IntPtr)0 && hDC != (IntPtr)0)
{
NativeMethods.ReleaseDC(hwnd, hDC);
}
}
#endif
}
#if !UNIX
@@ -3321,6 +3050,33 @@ namespace Microsoft.PowerShell
#endregion helper
#region
internal static int LengthInBufferCells(char c)
{
// The following is based on http://www.cl.cam.ac.uk/~mgk25/c/wcwidth.c
// which is derived from http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt
bool isWide = c >= 0x1100 &&
(c <= 0x115f || /* Hangul Jamo init. consonants */
c == 0x2329 || c == 0x232a ||
(c >= 0x2e80 && c <= 0xa4cf &&
c != 0x303f) || /* CJK ... Yi */
(c >= 0xac00 && c <= 0xd7a3) || /* Hangul Syllables */
(c >= 0xf900 && c <= 0xfaff) || /* CJK Compatibility Ideographs */
(c >= 0xfe10 && c <= 0xfe19) || /* Vertical forms */
(c >= 0xfe30 && c <= 0xfe6f) || /* CJK Compatibility Forms */
(c >= 0xff00 && c <= 0xff60) || /* Fullwidth Forms */
(c >= 0xffe0 && c <= 0xffe6));
// We can ignore these ranges because .Net strings use surrogate pairs
// for this range and we do not handle surrogage pairs.
// (c >= 0x20000 && c <= 0x2fffd) ||
// (c >= 0x30000 && c <= 0x3fffd)
return 1 + (isWide ? 1 : 0);
}
#endregion
#region SendInput
internal static void MimicKeyPress(INPUT[] inputs)
@@ -3396,9 +3152,6 @@ namespace Microsoft.PowerShell
#region Code Page
[DllImport(PinvokeDllNames.GetConsoleCPDllName, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern uint GetConsoleCP();
[DllImport(PinvokeDllNames.GetConsoleOutputCPDllName, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern uint GetConsoleOutputCP();
@@ -3413,15 +3166,6 @@ namespace Microsoft.PowerShell
[DllImport(PinvokeDllNames.ReleaseDCDllName, SetLastError = false, CharSet = CharSet.Unicode)]
internal static extern int ReleaseDC(HWND hwnd, HDC hdc);
[DllImport(PinvokeDllNames.TranslateCharsetInfoDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool TranslateCharsetInfo(IntPtr src, out CHARSETINFO Cs, DWORD options);
[DllImport(PinvokeDllNames.GetTextMetricsDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool GetTextMetrics(HDC hdc, out TEXTMETRIC tm);
[DllImport(PinvokeDllNames.GetCharWidth32DllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool GetCharWidth32(HDC hdc, uint first, uint last, out int width);
[DllImport(PinvokeDllNames.FlushConsoleInputBufferDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool FlushConsoleInputBuffer(NakedWin32Handle consoleInput);
@@ -3476,15 +3220,9 @@ namespace Microsoft.PowerShell
Pipe
};
[DllImport(PinvokeDllNames.GetFileTypeDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern FileType GetFileType(NakedWin32Handle fileHandle);
[DllImport(PinvokeDllNames.GetLargestConsoleWindowSizeDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern COORD GetLargestConsoleWindowSize(NakedWin32Handle consoleOutput);
[DllImport(PinvokeDllNames.GetStdHandleDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr GetStdHandle(int handleId);
[DllImport(PinvokeDllNames.ReadConsoleDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool ReadConsole
(
@@ -3563,10 +3301,6 @@ namespace Microsoft.PowerShell
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool GetCurrentConsoleFontEx(NakedWin32Handle consoleOutput, bool bMaximumWindow, ref CONSOLE_FONT_INFO_EX consoleFontInfo);
// There is no SetCurrentConsoleFontEx on Core
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool SetCurrentConsoleFontEx(NakedWin32Handle consoleOutput, bool bMaximumWindow, ref CONSOLE_FONT_INFO_EX consoleFontInfo);
[DllImport(PinvokeDllNames.GetConsoleCursorInfoDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool GetConsoleCursorInfo(NakedWin32Handle consoleOutput, out CONSOLE_CURSOR_INFO consoleCursorInfo);
@@ -251,13 +251,6 @@ namespace Microsoft.PowerShell
throw hostException;
}
#if !CORECLR
// The default font face used for Powershell Console is Lucida Console.
// However certain CJK locales dont support Lucida Console font. Hence for such
// locales the console font is updated to Raster dynamically.
ConsoleControl.UpdateLocaleSpecificFont();
#endif
s_theConsoleHost.BindBreakHandler();
PSHost.IsStdOutputRedirected = Console.IsOutputRedirected;