aardio 提供以下库或函数用于检测输入法与键盘状态:
我们先了解两个用于表示输入法状态的变量:
opened:
活动窗口收到 WM_IME_CONTROL, IMC_GETOPENSTATUS 消息返回的值。 用于表示当前是否打开中日韩等输入法。
convMode:
活动窗口收到 WM_IME_CONTROL, IMC_GETCONVERSIONMODE 消息返回的值。用于指示输入法的转换模式(中、英、标点符号、全角、半角等)。
1. 基本规则:
0/*_IME_CMODE_ALPHANUMERIC*/。中日韩等输入法关闭时,opened 应当返回 0。但 convMode 可能等于 1(IME_CMODE_NATIVE),也可能等于 0(IME_CMODE_ALPHANUMERIC) 。
例如对于中文输入法,只有 OpenStatus 为 1 并且
convMode & IME_CMODE_NATIVE才表示中文输入状态。
2. 中日韩文输入模式:
convMode & 1/*_IME_CMODE_NATIVE*/ 表示开启中日韩文输入模式。_IME_CMODE_NATIVE 还有 _IME_CMODE_CHINESE,_IME_CMODE_JAPANESE,_IME_CMODE_HANGUL 等别名。如果没有这个标志位则表示 0/*_IME_CMODE_ALPHANUMERIC*/ 这个标志位有效,也就是仍为英文输入模式。
开启中日韩文输入模式后:
convMode & 2/*IME_CMODE_KATAKANA*/ 表示日文片假名输入模式。convMode & 0x400/*IME_CMODE_SYMBOL*/ 表示中文标点模式。convMode & 0x100/*IME_CMODE_NOCONVERSION*/表示关闭输入法,这时候即使 opened 为 1 仍然表示关闭输入法( 英文输入模式 )。这种用法比较罕见。 3. 英文标点全半角状态:
convMode & 8/*IME_CMODE_FULLSHAPE*/ 为英文全角标点,反之则为英文半角状态。convMode 还有一些其他状态,中文输入法一般用不到。
4. 键盘布局语言:
如果键盘布局返回错误的语言 ID,则检测到的输入法状态也会是错误的。中文输入法打开以后,无论中英输入模式,键盘布局( HKL )的语言 ID 都应是 0x804, 这与操作系统输入法设置中,中文输入法只能自中文键盘中添加的规则一致。
有些老旧的输入法会强行添加「简体中文美式键盘」,这是不妥的,安装这种输入法会导致输入状态与键盘布局错乱。实际上 Windows 10 开始已经移除了这个键盘,应改为「英文美式键盘」。
个别输入法会返回错误的状态,主要分为以下三种情况:#
可尝试在不同窗口切换一下英文全半角、中英文标点等并查看 ImTip 能否正确显示状态,多切换几个窗口如果出错就是有问题。第 1、第 2 种情况可以在 ImTip 中勾选怪异模式解决( 不能同时安装多个有问题的输入法,因为 ImTip 会检测输入法列表并自动切换不同的兼容模式 ),第 3 种情况可能是该输入法问题比较严重,勾选怪异模式无法解决。
至于第三方输入法工具则更为混乱,早年我写过文章,在 ImTip 发布之前网上流传的代码基本都是错的。例如有的开发者看到中文状态下 convMode 是某个数值就以为这个固定的数值就表示中文输入状态,其实这是未经过严谨测试望文生义,别人切换几个状态或者换个输入法你的程序就乱套了。
ImTip 检测输入法状态的功能由 aardio 标准库的 key.ime.state 函数提供,此函数的关键源码如下:
namespace key.ime{
conversionLangIds = {[0x804] = 0x409;[0x404] = 0x409;[0xC04] = 0x409;[0x1404] = 0x409;[0x412] = 0x409;[0x0411] = 0x409} ;
state = function(hwnd){
if(!hwnd) {
hwnd = ::User32.GetForegroundWindow();
if(..winex) hwnd = ..winex.getFocus(hwnd,true) : hwnd;
}
var opened = getOpenStatus(hwnd);
var convMode = getConversionMode(hwnd);
var langId = getCurrentLangIdByHwnd(hwnd);
if (opened && langId==0x409) opened = false;
if(convMode === null) return false,,langId;
var symbolMode = 1/*_IME_SYMBOLMODE_HALFSHAPE*/;
if(!opened && (convMode==1 || convMode==0 ) && ! conversionLangIds[langId] ) symbolMode = 0;
elseif( (convMode & 0x400/*_IME_CMODE_SYMBOL*/) && opened ) symbolMode = 3/*_IME_SYMBOLMODE_SYMBOL*/;
elseif(convMode & 8/*_IME_CMODE_FULLSHAPE*/) symbolMode = 2/*_IME_SYMBOLMODE_FULLSHAPE*/;
elseif(convMode & 0x100/*_IME_CMODE_NOCONVERSION*/) opened = false;
/*
首个返回值为是否启用输入转换(例如输入中、日、韩等文字),false 为英文输入状态,
第二个返回值 symbolMode 用一个数值表示标点模式:
1. 英文半角标点
2. 英文全角标点
3. 中文标点
0. 或 null 已关闭输入转换
*/
return opened && (convMode & 3/*_IME_CMODE_LANGUAGE*/),symbolMode,langId,convMode;
}
}