Windows 为 ANSI 版本 WM_CHAR 生成 UTF8 序列?为什么我看不到它?

Windows producing UTF8 sequence for ANSI version WM_CHAR? Why I cannot see it?

提问人:Jimm Chen 提问时间:1/21/2023 最后编辑:Jimm Chen 更新时间:1/22/2023 访问量:303

问:

在今天(2023.01)的MSDN https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-char 中,Microsoft说:

...否则(使用 RegisterClass 的 ANSI 版本),系统会在当前进程代码页中提供字符,在 Windows 版本 1903(2019 年 5 月更新)及更高版本中可以将其设置为 UTF-8

但是,我只是看不到WM_CHAR以 UTF8 序列呈现 Unicode 字符。是我做错了,还是文档错误/误导?

我在Win10.21H2上使用Keyview2A.exe v1.8进行实验,它基于Charles Petzold在他的著名著作Programming Windows 5th-ed(1998)中的Keyview2演示程序。

我正在尝试 Win10.21H2 .

首先,非UTF8ACP情况表明 KeyviewA 工作正常。

我尝试输入一个汉字,即 U+7535,并输入 GBK 编码。B5 E7

non-UTF8APC, type in a non-ASCII char

non-UTF8APC, OK we get ANSI sequence in codepage 936

其次,UTF8ACP情况没有给出 KeyviewA UTF8 序列。

我刚刚得到0x3F(?),唉!

UTF8ACP, type in a Unicode char

UTF8ACP, does not see UTF8 sequence in WM_CHAR

第三,SBCS中的那些角色呢?

SBCS = 单字节字符集。 DBCS = 双字节字符集。 MBCS = 多字节字符集。(SBCS、DBCS 和 3+ 字节字符集的通用名称)

大多数欧洲国家/地区都使用此类字符集。

输入一些俄语字母:

Type in some Russian letters.

输入一些希腊字母:

Type in some Greek letters

[20230121.C1]到目前为止,我似乎已经找到了关于 ANSI(窄字符)程序的“启用UTF8ACP”的规则。总结如下:

IME 为任何人工输入字符生成 Unicode 值。当 Windows 需要将该字符发送到 KeyviewA 时,它会执行以下操作:

  • 检查目标 HWND 的 HKL 值。备注:KeyviewA 本身可以通过 查询此 HKL 值。GetKeyboardLayout(0)
  • 获取与 HKL 值关联的 ANSI 代码页(我们称之为 )。这可以通过 获得。curhklcurcodepage=GetLocaleInfo(LOWORD(curhkl), LOCALE_IDEFAULTANSICODEPAGE, ...);
  • 调用以将 Unicode 值转换为 MBCS 序列。WideCharToMultiByte(curcodepage, ...)
    • 如果 MBCS 是单个字节(例如 0xE1),则 Windows 会向 Keyview2A 发送一条WM_CHAR消息,其中包含 wParam=0xE1 。
    • 如果 MBCS 是两个字节(例如 0xB5 0xE7),则 Windows 向 Keyview2A 发送两条WM_CHAR消息,其中 wParam=0x3F,两者都是。
WinAPI Unicode

评论

0赞 GSerg 1/21/2023
该程序是否检测到WM_UNICHAR
0赞 JosefZ 1/21/2023
相关新闻: stackoverflow.com/questions/71431386
0赞 GSerg 1/21/2023
@JosefZ 是吗?
0赞 Jimm Chen 1/21/2023
@GSerg我试图捕捉WM_UNICHAR,就像我的这个问题 [stackoverflow.com/q/75186875/151453] 一样,但我从未收到过,无论是在 Keyview2A 还是在 Keyview2U 中。
0赞 Adrian McCarthy 1/22/2023
也许将WM_IME_CHAR添加到按键查看器程序记录的键盘消息将有助于显示正在发生的事情。

答:

4赞 Jimm Chen 1/21/2023 #1

经过一番调查,看来我需要回答我自己的问题。答案是你我仅通过阅读MSDN无法获得的东西。

我确实在 ANSI WM_CHAR中看到了 UTF8,但以一种令人惊讶的方式。

  • 首先,在 Windows 10 上打开UTF8ACP。
  • 其次,添加藏语(藏语)键盘布局。
  • 第三,运行Keyview2A v1.9(ANSI版本),我刚刚更新了它来处理这种情况。

现在,在 Keyview2A 中输入一些藏文字符,我们看到 UTF8 序列出现。

Add Tibetan keyboard layout

Type some Tibetan characters into Keyview2A

你看?三个 UTF8 字节在单个 WM_CHAR 消息中发送,而不是在三个WM_CHAR消息中发送。这个想法是可以的,因为一个 UTF8 序列的最大长度为 4 个字节,可以隐藏在 WPARAM 中。

现在将其与 Keyview2U(Unicode 版本)进行比较,无论UTF8ACP打开还是关闭:

Type some Tibetan characters into Keyview2U

好的,U+0F45 是 UTF8 [E0 BD 85],它们匹配。

值得一提的是:

  • 如果 Keyview2A 在 UTF8ACP-off 环境中运行,它仍然会在WM_CHAR中获取 0x3F()。?
  • 为什么藏语如此特别?我认为这是因为业界从未为藏语定义过代码页(就叫它页字符集)。要对藏文文本进行编码,您必须以 Unicode 对其进行编码。除了藏语,我认为还有孟加拉语、古吉拉特语、泰米尔语等。
  • 是否每个无代码页字符集都会在一条WM_CHAR消息中生成 UTF8 序列?不,正如我后来发现的那样!阿姆哈拉语(在埃塞俄比亚使用)就是一个例子。它在一系列WM_CHAR消息中发送 UTF8 序列,每条消息对应一个字节。见下图。

UTF8ACP, typing an Amharic letter

——真是该死的不一致!

今天的最后一句话,你不认为Microsoft对 ANSI WM_CHAR 的UTF8ACP增强是蹩脚的吗?它使 Keyview2A 能够看到无代码页字符集(如藏语)的 UTF8 序列,但不允许它看到那些 has-codepage 字符集的 UTF8 序列(你在上面的问题中看到,Keyview2A 为一个中文 GBK 字符获得两个0x3F)——真的很荒谬。

我真的希望 Keyview2A 能够为每个WM_CHAR获得 UTF8 序列——并破坏许多遗留应用程序(通过接收非 ASCII 字符的错误字节序列),大多数人认为这就是UTF8ACP应该的意思。难怪Microsoft仍然将UTF8ACP功能标记为“Beta”,我猜 Beta 状态会持续很多年,也许是 10~20 年。

评论

2赞 Mark Ransom 1/21/2023
是的,Microsoft 对 UTF-8 的支持很糟糕。多年来,您一直能够将代码页设置为 65001,但据报道它非常有问题,我猜您刚刚被这些错误绊倒了。这是一种不幸的状态,因为 UTF-8 是一种非常美妙的编码,并且 *nix 的所有风格几乎都采用了它。