如何检测键盘输入代码页

时间:2014-05-20 05:59:01

标签: c# wpf unicode codepages input-language

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

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

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

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

1 个答案:

答案 0 :(得分:2)

免责声明:我不是.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并更新缓存的值作为响应。