2

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

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

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

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

4

1 回答 1

3

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

要确定与特定键盘布局关联的代码页,您可以调用 Win32GetLocaleInfo函数,指定与当前键盘布局关联的语言 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 的现代版本中,微软已经转向命名语言环境,首先是因为它们没有足够的空间容纳数字 ID,其次是为了支持自定义语言环境。但是您需要使用旧功能来完成您的工作。现代 Windows 应用程序也不使用 ANSI 代码页。

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

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

于 2014-05-20T07:21:24.063 回答