提问人:Jimm Chen 提问时间:1/21/2023 最后编辑:Jimm Chen 更新时间:1/22/2023 访问量:303
Windows 为 ANSI 版本 WM_CHAR 生成 UTF8 序列?为什么我看不到它?
Windows producing UTF8 sequence for ANSI version WM_CHAR? Why I cannot see it?
问:
在今天(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
其次,UTF8ACP情况没有给出 KeyviewA UTF8 序列。
我刚刚得到0x3F(?),唉!
第三,SBCS中的那些角色呢?
SBCS = 单字节字符集。 DBCS = 双字节字符集。 MBCS = 多字节字符集。(SBCS、DBCS 和 3+ 字节字符集的通用名称)
大多数欧洲国家/地区都使用此类字符集。
输入一些俄语字母:
输入一些希腊字母:
[20230121.C1]到目前为止,我似乎已经找到了关于 ANSI(窄字符)程序的“启用UTF8ACP”的规则。总结如下:
IME 为任何人工输入字符生成 Unicode 值。当 Windows 需要将该字符发送到 KeyviewA 时,它会执行以下操作:
- 检查目标 HWND 的 HKL 值。备注:KeyviewA 本身可以通过 查询此 HKL 值。
GetKeyboardLayout(0)
- 获取与 HKL 值关联的 ANSI 代码页(我们称之为 )。这可以通过 获得。
curhkl
curcodepage=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,两者都是。
答:
经过一番调查,看来我需要回答我自己的问题。答案是你我仅通过阅读MSDN无法获得的东西。
我确实在 ANSI WM_CHAR中看到了 UTF8,但以一种令人惊讶的方式。
- 首先,在 Windows 10 上打开UTF8ACP。
- 其次,添加藏语(藏语)键盘布局。
- 第三,运行Keyview2A v1.9(ANSI版本),我刚刚更新了它来处理这种情况。
现在,在 Keyview2A 中输入一些藏文字符,我们看到 UTF8 序列出现。
你看?三个 UTF8 字节在单个 WM_CHAR 消息中发送,而不是在三个WM_CHAR消息中发送。这个想法是可以的,因为一个 UTF8 序列的最大长度为 4 个字节,可以隐藏在 WPARAM 中。
现在将其与 Keyview2U(Unicode 版本)进行比较,无论UTF8ACP打开还是关闭:
好的,U+0F45 是 UTF8 [E0 BD 85],它们匹配。
值得一提的是:
- 如果 Keyview2A 在 UTF8ACP-off 环境中运行,它仍然会在WM_CHAR中获取 0x3F()。
?
- 为什么藏语如此特别?我认为这是因为业界从未为藏语定义过代码页(就叫它页字符集)。要对藏文文本进行编码,您必须以 Unicode 对其进行编码。除了藏语,我认为还有孟加拉语、古吉拉特语、泰米尔语等。
- 是否每个无代码页字符集都会在一条WM_CHAR消息中生成 UTF8 序列?不,正如我后来发现的那样!阿姆哈拉语(在埃塞俄比亚使用)就是一个例子。它在一系列WM_CHAR消息中发送 UTF8 序列,每条消息对应一个字节。见下图。
——真是该死的不一致!
今天的最后一句话,你不认为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 年。
评论
WM_UNICHAR
?