rime / weasel

【小狼毫】Rime for Windows
https://rime.im
GNU General Public License v3.0
4.48k stars 548 forks source link

小狼毫未能正确处理WM_IME_CONTROL相关消息 #1371

Open oTnTh opened 3 weeks ago

oTnTh commented 3 weeks ago

我在其他几个issues里看到有人在讨论,如何用代码控制输入法状态的问题。然后去做了一点功课,发现WM_IME_CONTROL消息可以实现该功能,但是小狼毫似乎没有正确处理该消息。

在Widnows平台上,可以用ImmGetDefaultIMEWnd获得输入法句柄,然后通过向该句柄发送WM_IME_CONTROL消息的方式,获得和控制输入法的状态(切换中英文输入状态,全角半角切换等)。

以下是用python写的完整示例:

import win32more.Windows.Win32.UI.WindowsAndMessaging as wm
import win32more.Windows.Win32.UI.Input.Ime as ime

IMC_GETCONVERSIONMODE = 1
IMC_SETCONVERSIONMODE = 2
IMC_GETOPENSTATUS = 5

hwnd = wm.GetForegroundWindow()
himc = ime.ImmGetDefaultIMEWnd(hwnd)

ret = wm.SendMessage(himc, wm.WM_IME_CONTROL, IMC_GETOPENSTATUS, 0)
print('open:', ret)

ret = wm.SendMessage(himc, wm.WM_IME_CONTROL, IMC_GETCONVERSIONMODE, 0)
print('conv:', ret)
print('\tNATIVE', (ret & ime.IME_CMODE_NATIVE))
print('\tKATAKANA', (ret & ime.IME_CMODE_KATAKANA))
print('\tLANGUAGE', (ret & ime.IME_CMODE_LANGUAGE))
print('\tFULLSHAPE', (ret & ime.IME_CMODE_FULLSHAPE))
print('\tROMAN', (ret & ime.IME_CMODE_ROMAN))
print('\tCHARCODE', (ret & ime.IME_CMODE_CHARCODE))
print('\tHANJACONVERT', (ret & ime.IME_CMODE_HANJACONVERT))
print('\tSOFTKBD', (ret & ime.IME_CMODE_SOFTKBD))
print('\tNOCONVERSION', (ret & ime.IME_CMODE_NOCONVERSION))
print('\tEUDC', (ret & ime.IME_CMODE_EUDC))
print('\tSYMBOL', (ret & ime.IME_CMODE_SYMBOL))
print('\tFIXED', (ret & ime.IME_CMODE_FIXED))

#ret = wm.SendMessage(himc, wm.WM_IME_CONTROL, IMC_SETCONVERSIONMODE, ime.IME_CMODE_ALPHANUMERIC)
#ret = wm.SendMessage(himc, wm.WM_IME_CONTROL, IMC_SETCONVERSIONMODE, ime.IME_CMODE_NATIVE)

下面这些定义Windows SDK里似乎没有,不过相关功能好像一直都可以用。

IMC_GETCONVERSIONMODE = 1
IMC_SETCONVERSIONMODE = 2
IMC_GETOPENSTATUS = 5

因为没有找到准确的文档,所以我就对比了一下微软拼音和小狼毫的返回值。

ret = wm.SendMessage(himc, wm.WM_IME_CONTROL, IMC_GETOPENSTATUS, 0)
print('open:', ret)

微软拼音中不管输入模式是中文还是英文,IMC_GETOPENSTATUS的返回值都是1

小狼毫打开ascii_mode时返回1,没有问题。但是中文输入模式返回0,这里应该不太对。

open: 1
conv: 1033
    NATIVE 1
    KATAKANA 0
    LANGUAGE 1
    FULLSHAPE 8
    ROMAN 0
    CHARCODE 0
    HANJACONVERT 0
    SOFTKBD 0
    NOCONVERSION 0
    EUDC 0
    SYMBOL 1024
    FIXED 0

后面的部分微软拼音的返回值大概是上面这样,猜测各值的意义是:

经过测试,可以通过组合上面各值的方式改变微软拼音的状态。

如果只是想切换中英文输入模式,可以直接单独发送IME_CMODE_NATIVE,可以成功切到中文输入状态,跟按Ctrl+Space的效果一样。

如果能提供WM_IME_CONTROL的相关支持,应该就能兼容市面上不少控制输入法状态的第三方工具了。只是不知道是不是还会出现某些方案没有“全角半角”和“中英文标点”的情况。

hoodlum1980 commented 1 week ago

这是我对某个“文字输入”窗口 (hWndTarget)关闭“中文输入法”的代码(也就是切换到英文输入状态),对应的输入法应该是系统自带的微软拼音输入法,供参考~。~

HWND hCurWnd = ImmGetDefaultIMEWnd(hWndTarget);
if(SendMessage(hCurWnd, WM_IME_CONTROL, IMC_GETOPENSTATUS, 0))
{
    SendMessage(hCurWnd, WM_IME_CONTROL, IMC_SETOPENSTATUS, 0);
    // 已经切换到英文输入法。
}