c# - 如何检测键盘输入代码页

标签 c# wpf unicode codepages input-language

当用户将数据输入应用程序字段时,我需要检测键盘输入正在使用的代码页。

我尝试使用System.Text.Encoding.Default.CodePage;,但它提供了区域设置中配置的代码页。

然后我认为 Console.InputEncoding.CodePage; 可以工作,但代码页仍然与上面的示例相同。

问题是,由于区域设置的原因,用户可能有西里尔文 (Windows-1251) 代码页,但他可能希望使用不同的输入语言。用户输入的数据然后保存到文件中,并且可以在具有不同区域设置的系统中打开该文件。除了文本之外,我还保存代码页号,以便我的应用程序可以加载文件并正确显示文本。我无法使用 Unicode 与不支持 unicode 的其他应用程序交叉兼容。

最佳答案

免责声明:我不是 .NET Framework 全局化方面的专家,因此它可能在某个地方包装了等效的功能。如果是这样,并且您可以找到它,那就太好了,请使用它。我想也许 Globalization.CultureInfo.CurrentCulture 会返回我们正在寻找的信息,但可惜它没有;相反,即使键盘布局发生更改,它似乎也会返回系统默认区域性。我停止了调查。尽管需要一些额外的代码,但所描述的方法保证可以工作。

要确定与特定键盘布局关联的代码页,您可以调用 Win32 GetLocaleInfo function ,指定与当前键盘布局关联的语言 ID。您可以使用 LOCALE_IDEFAULTANSICODEPAGE 常量请求此操作。

要从 .NET 应用程序调用这些函数,您需要使用 P/Invoke。您还需要为一些基本宏定义等效函数。

const int LOCALE_IDEFAULTANSICODEPAGE = 0x1004;
const int LOCALE_RETURN_NUMBER        = 0x20000000;
const int SORT_DEFAULT                = 0x0;

static int LOWORD(IntPtr val)
{
   return (unchecked((int)(long)val)) & 0xFFFF;
}

static int MAKELCID(int languageID, int sortID)
{
   return ((0xFFFF & languageID) | (((0x000F) & sortID) << 16));
}

static int MAKELANGID(int primaryLang, int subLang)
{
   return ((((ushort)(subLang)) << 10) | (ushort)(primaryLang));
}

[DllImport("kernel32.dll", SetLastError = true)]
static extern int GetLocaleInfo(int locale,
                                 int lcType,
                                 out uint lpLCData,
                                 int cchData);

[DllImport("user32.dll")]
static extern IntPtr GetKeyboardLayout(uint idThread);

像这样使用它:

// Get the keyboard layout for the current thread.
IntPtr keybdLayout = GetKeyboardLayout(0);

// Extract the language ID from it, contained in its low-order word.
int langID = LOWORD(keybdLayout);

// Call the GetLocaleInfo function to retrieve the default ANSI code page
// associated with that language ID.
uint codePage = 0;
GetLocaleInfo(MAKELCID(langID, SORT_DEFAULT),
               LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
               out codePage,
               Marshal.SizeOf(codePage));

使用美国英语键盘布局进行测试时,codePage 为 1252。切换到希腊键盘布局后,codePage 为 1253。同样,土耳其语返回 1254,并且各种西里尔语言返回 1251。与记录的完全一致。

值得注意的是,在链接文档中,这些 API 函数被指示为已被取代。在 Windows 的现代版本中,Microsoft 已转向命名区域设置,首先是因为它们没有足够的空间容纳数字 ID,其次是为了支持自定义区域设置。但您将需要使用旧函数来完成您正在做的事情。现代 Windows 应用程序也不使用 ANSI 代码页。

但是,您确实需要意识到这一事实,因为它可能会反过来咬您一口。有些键盘布局没有关联的 ANSI 代码页。对于这些,只能使用 Unicode。上述代码将返回CP_ACP(相当于数值0)。处理这件事取决于你。您要么需要显示错误,要么将文件保存为 Unicode(尽管会破坏其他应用程序,但符合用户期望)。

最后,我必须指出,如果您缓存codePage值,它可能会变得过时,因为用户可以随时更改键盘布局。最简单的方法可能是不缓存该值,而是在每次执行保存时确定它。但如果你想缓存它,你将需要处理 WM_INPUTLANGCHANGE message并更新您的缓存值作为响应。

关于c# - 如何检测键盘输入代码页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23752037/

相关文章:

c# - 异步等待线程内部

wpf - FlowDocument 重复表头

WPF 如何让 UserControl 继承 Button?

unicode - 如何在 Rust 中检查字符是否为 Unicode 换行符(不仅是 ASCII)?

ios - SQLite 中的越南语 Unicode 文本搜索

c# - 微软应用中心 : How get list of users with session duration?

c# - 在 C# 中使用 xpath 选择具有不同类的多个 div 节点

C# Linq 返回对象

WPF:我可以重新设置复选框模板的样式吗,以便检查指示器变为红十字

c# - 从 C# "Unicode"字符串中删除除字母和数字之外的所有字符