Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(tsf): ime status #1499

Merged
merged 2 commits into from
Feb 22, 2025
Merged

fix(tsf): ime status #1499

merged 2 commits into from
Feb 22, 2025

Conversation

wzv5
Copy link
Contributor

@wzv5 wzv5 commented Feb 16, 2025

fix #1486

现在能正确响应 ImmSetOpenStatusImmSetConversionStatus,也能正确支持 ImTip,但是依然发现以下问题:

  1. WeaselServer.exe 管理下的托盘图标和悬浮状态图标更新有问题,看了眼 RimeWithWeasel 的实现。。呃,我放弃了。。耦合太强了。
  2. 对于 keyboard open,微软拼音是在获得焦点时无脑 open 并切换为中文输入,但是这样就与 ImmSetConversionStatus 冲突,调用输入法的程序无法通过 api 切换为英文输入,想了想还是不跟了,影响太大。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 16, 2025

顺便把易语言写的测试程序也发上来吧,如果有人想测试的话可以用。

imetest.zip

Snipaste_2025-02-16_18-43-26
Snipaste_2025-02-16_18-42-33

@wzv5 wzv5 changed the title fix(tsf): ime status [wip] fix(tsf): ime status Feb 17, 2025
@wzv5
Copy link
Contributor Author

wzv5 commented Feb 17, 2025

又发现点兼容性问题,等我再多测试一下。

@wzv5 wzv5 marked this pull request as draft February 17, 2025 03:38
@popyoung
Copy link

又发现点兼容性问题,等我再多测试一下。

也给我个版本用用看?

@lotem
Copy link
Member

lotem commented Feb 17, 2025

不懂了。
就問能不能跟 Rime 的 ascii_mode 同步?

@lotem
Copy link
Member

lotem commented Feb 17, 2025

Imm* 不是過時了嗎?爲什麼 TSF 輸入法還要看?也許微軟做得沒錯。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 17, 2025

Imm* 不是過時了嗎?爲什麼 TSF 輸入法還要看?也許微軟做得沒錯。

过时的只是 ime 输入法框架,微软不推荐再使用 ime 制作输入法。
而 ime 客户端 api 是没有过时的,ime 客户端 api 经过转换,实际是转发给了 tsf。

已经改好了,我再多测试一下。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 17, 2025

现在应该没问题了。

之前发现的问题是,如果处于键盘处于 close & native 状态,imtip 始终显示为英文状态,但其实是中文状态。

然后学微软拼音,在获得焦点时无脑打开键盘,但保留 ascii 状态,这样或许更加友好。

@wzv5 wzv5 changed the title [wip] fix(tsf): ime status fix(tsf): ime status Feb 17, 2025
@wzv5 wzv5 marked this pull request as ready for review February 17, 2025 05:33
@lotem lotem requested a review from fxliang February 17, 2025 06:20
@fxliang
Copy link
Contributor

fxliang commented Feb 17, 2025

这个有原来的需求要ctrl+space切换ascii和开关输入法可配置,目前的代码可以实现兼容这个吗?

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 17, 2025

这个有原来的需求要ctrl+space切换ascii和开关输入法可配置,目前的代码可以实现兼容这个吗?

有没有具体的软件来测试,测试兼容性还得看具体软件。

@fxliang
Copy link
Contributor

fxliang commented Feb 17, 2025

#1364 看这个pr的内容,通过注册表里的项目,可选是否让ctrl+space开关输入法,还是切换ascii的

这个有原来的需求要ctrl+space切换ascii和开关输入法可配置,目前的代码可以实现兼容这个吗?

有没有具体的软件来测试,测试兼容性还得看具体软件。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 17, 2025

#1343 (comment) 这里提到:

微软拼音中,只要“中/英文模式切换”中不勾选Ctrl+Space,VSCode等IDE中,都可以用这一组快捷键触发自动完成的功能。

我也发现微软拼音会忽略 ctrl+space,按这个issue里的讨论,我觉得更好的方案是直接无视掉 KEYBOARD_OPENCLOSE 消息,只处理 INPUTMODE_CONVERSION,这样的效果好像就跟微软拼音一样了。
反正微软拼音在获得焦点时就无脑 open 了,无视掉 KEYBOARD_OPENCLOSE 也可以理解。
如果用户真想通过 ctrl+space 切换中英文状态,可以在 librime 里实现。

这个 pr 暂时先放着,我试试无视 KEYBOARD_OPENCLOSE 消息之后的兼容性如何。

@fxliang
Copy link
Contributor

fxliang commented Feb 17, 2025

#1343 (comment) 这里提到:

微软拼音中,只要“中/英文模式切换”中不勾选Ctrl+Space,VSCode等IDE中,都可以用这一组快捷键触发自动完成的功能。

我也发现微软拼音会忽略 ctrl+space,按这个issue里的讨论,我觉得更好的方案是直接无视掉 KEYBOARD_OPENCLOSE 消息,只处理 INPUTMODE_CONVERSION,这样的效果好像就跟微软拼音一样了。 反正微软拼音在获得焦点时就无脑 open 了,无视掉 KEYBOARD_OPENCLOSE 也可以理解。 如果用户真想通过 ctrl+space 切换中英文状态,可以在 librime 里实现。

这个 pr 暂时先放着,我试试无视 KEYBOARD_OPENCLOSE 消息之后的兼容性如何。

不少用户会想要Ctrl+空格切换ascii 所以之前的pr改成这个状态,如果要维持之前的开关输入法的状态可以手动修改下设定

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 17, 2025

不少用户会想要Ctrl+空格切换ascii 所以之前的pr改成这个状态,如果要维持之前的开关输入法的状态可以手动修改下设定

那个注册表设置跟微软拼音的行为并不一样,微软拼音是直接无视了 KEYBOARD_OPENCLOSE 消息,就不存在close这个状态,一直都是open。
实测无视 KEYBOARD_OPENCLOSE 消息之后,在 librime 中配置的 ctrl+space 快捷键是可以生效的,切换中英文状态没问题。
但是如果 librime 中没有配置 ctrl+space,调用输入法的程序并不能收到这个按键消息,不知道是被系统吃了还是被 librime 吃了, @fxliang 你有头绪么?如果能把 ctrl+space 透传到用户程序里就完美了。

@fxliang
Copy link
Contributor

fxliang commented Feb 17, 2025

不少用户会想要Ctrl+空格切换ascii 所以之前的pr改成这个状态,如果要维持之前的开关输入法的状态可以手动修改下设定

那个注册表设置跟微软拼音的行为并不一样,微软拼音是直接无视了 KEYBOARD_OPENCLOSE 消息,就不存在close这个状态,一直都是open。 实测无视 KEYBOARD_OPENCLOSE 消息之后,在 librime 中配置的 ctrl+space 快捷键是可以生效的,切换中英文状态没问题。 但是如果 librime 中没有配置 ctrl+space,调用输入法的程序并不能收到这个按键消息,不知道是被系统吃了还是被 librime 吃了, @fxliang 你有头绪么?如果能把 ctrl+space 透传到用户程序里就完美了。

这个组合键是可以用户配置的,暂无想法

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 17, 2025

调试出来了,是被系统吃掉的,具体来说是 weasel 收到了完整按键消息,librime 也能正确处理,但 weasel 把按键消息放行后,用户程序收不到按下消息,但能收到松开消息。
不知道为啥微软拼音可以透传过去,也许是系统开了后门吧。。

现在测试出来的情况是,最佳方案就是像微软拼音一样,无视掉 KEYBOARD_OPENCLOSE 消息,并且在获得焦点时强制 open。
如果用户希望使用 ctrl+space 切换中英文状态,就在 librime 里配置。就像微软拼音只使用自己uwp里的设置,不遵守传统win32里的设置。
如果用户希望透传 ctrl+space,就必须在系统设置里把这个快捷键设置为其他,比如 ctrl+pageup,不然系统会吃掉 ctrl+space 按下事件。

大家觉得这样如何?

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 17, 2025

最终就这样了,不再改了。。没想到一个小问题竟然引出一大堆其他问题。
现在这样就是最贴近微软拼音的做法,跟随微软拼音的行为总不会错。

修改内容如下:

  1. 无视 KEYBOARD_OPENCLOSE 消息,并且在获得焦点时强制 open。
  2. 能够正确处理 ImmSetConversionStatus,虽然不再响应 ImmSetOpenStatus,但总比之前的错误响应要好。
  3. 删除 ToggleImeOnOpenClose 注册表选项,微软拼音不存在 close 状态,始终为 open。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 18, 2025

找到一种简单可行的方式来向用户程序透传 ctrl+space,在 WeaselTSF::_ProcessKeyEvent 中添加:

if (ke.keycode == ibus::space && (ke.mask & ibus::CONTROL_MASK) &&
    !(ke.mask & ibus::RELEASE_MASK) && !*pfEaten) {
  // TODO: 从注册表读取系统设置里的快捷键,如果是 ctrl+space 才模拟发送
  HWND hwnd = _GetFocusedContextWindow();
  PostMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
}

这样修改后,行为就和微软拼音完全一致了。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 18, 2025

@fxliang 你试试现在这样,我今天用了一天了,很完美,跟微软拼音一模一样了。
这样修改之后,之前那些关于 ctrl+space 的 issue 都可以关闭了。

@fxliang
Copy link
Contributor

fxliang commented Feb 18, 2025

@fxliang 你试试现在这样,我今天用了一天了,很完美,跟微软拼音一模一样了。 这样修改之后,之前那些关于 ctrl+space 的 issue 都可以关闭了。

大概看了下,硬编了ctrl+space,如果用户改了其他快捷键可能失效了;还有,原来有用户就是要关闭输入法状态的需求如何处理?要再了解细一点再看怎么解,会比较好

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 18, 2025

大概看了下,硬编了ctrl+space,如果用户改了其他快捷键可能失效了;还有,原来有用户就是要关闭输入法状态的需求如何处理?要再了解细一点再看怎么解,会比较好

  1. 硬编ctrl+space是因为各种ide都依赖这个快捷键,比较重要,所以做单独处理。如果用户改了其他快捷键那就更好了,就不用模拟按键了。当然用户设置的快捷键也不会生效,这是预期行为,就是要作废掉高级键盘设置里的切换快捷键。微软也是这么干的。
  2. 关闭输入法和切换ascii在实际使用上没有区别,关闭这个功能我猜大概率是微软为了兼容历史代码留下的,现在不应该再使用了,微软自己都不用。如果用户希望按ctrl+space切换ascii状态,在librime里配置即可。
  3. 再补充说明一下高级键盘设置里的切换快捷键,这也是一个历史遗留功能,微软自己都不遵守,所以我们也只用librime里的ascii切换快捷键就行。

@popyoung
Copy link

能否先发个dll给我,每天被这个问题困扰……

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 19, 2025

能否先发个dll给我,每天被这个问题困扰……

呃,CI里就有安装包。
https://github.com/rime/weasel/actions/runs/13404999086

@popyoung
Copy link

能否先发个dll给我,每天被这个问题困扰……

呃,CI里就有安装包。 https://github.com/rime/weasel/actions/runs/13404999086

原来如此,action不熟,不好意思。

@fxliang
Copy link
Contributor

fxliang commented Feb 20, 2025

_status.ascii_mode = !_IsKeyboardOpen();
这个处理要再改改增加一点场景,初始化session, 重新连接,更换schema的时候要缓存出来另外一种方式来处理

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

键盘开关和ascii_mode 是两种状态

我们不是在讨论 /toggleascii 这个分支么,键盘开关就是和 ascii 状态挂钩,开=中文,关=英文。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

_status.ascii_mode = !_IsKeyboardOpen(); 这个处理要再改改增加一点场景,初始化session, 重新连接,更换schema的时候要缓存出来另外一种方式来处理

引用上面 @popyoung 的回复:

个人认为就算要改,也最好独立一个版本,分开pr。现在单独改一个问题最好不过。

@lotem
Copy link
Member

lotem commented Feb 20, 2025

可以暫時不關注在西文(ascii_mode)狀態下做轉換的需求。
但是西文狀態 librime 仍然處理按鍵,快捷鍵還是管用的。

希望 Control+space 不禁用輸入法的用家,想要的大概是 Control+space 與其他方式(如單擊 Shift)切換中西文等效吧。
那麼 Control+space 切到西文模式之後,應該可以用其他快捷鍵切回中文。
不然,就不能把這個狀態和西文混爲一談。


那麼問題來了:_KeyboardOpen() 爲 FALSE 以後的按鍵究竟能不能發給 librime?

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

我想提醒大家一点,之前的提交里我也说过:
如果 app 使用 tsf 框架,那么 weasel 是收不到 ctrl+space 按键事件的。
如果 app 使用传统 ime 框架,weasel 就可以收到按键事件。
纠结 ctrl+space 到底能不能传给 librime 本就是无意义的,如果 app 使用 tsf 框架,那无论如何就是传不到,除非自己伪造一个按键事件。

@lotem
Copy link
Member

lotem commented Feb 20, 2025

先別管 Control+space 能不能傳過去了。默認配置也沒綁定這個鍵。
後續的按鍵 librime 能不能收到。這一點很關鍵。

微軟很可能有直接處理 Control+space 的方法,而不是在 GUID_COMPARTMENT_KEYBOARD_OPENCLOSE 處處理。
如果沒別的辦法,我看 /toggleascii 只能做到忽略程序打開鍵盤的請求;而程序控制關閉鍵盤跟用戶按 Control+space 無法區分,結果只能翻轉一次 ascii_mode

    if (!_KeyboardOpen()) {
        _status.ascii_mode = !_status.ascii_mode;
       _SetKeyboardOpen(true);
    }

@fxliang
Copy link
Contributor

fxliang commented Feb 20, 2025

目前的改动确认是会break #1364 所以目前我觉得未可合并

至于上面的判断是不是真不真,都可以插入一些OutputDebugString来验证

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

算了,我录一段视频吧,证明在 GUID_COMPARTMENT_KEYBOARD_OPENCLOSE 里调用 _SetKeyboardOpen(true) 是无效的。

aaa

这是 0.16.3 原版,哪怕调用了 _SetKeyboardOpen(true),也还是close状态。

@lotem
Copy link
Member

lotem commented Feb 20, 2025

GUID_COMPARTMENT_KEYBOARD_OPENCLOSE 里调用 _SetKeyboardOpen(true) 是无效的。
这是 0.16.3 原版,哪怕调用了 _SetKeyboardOpen(true),也还是close状态。

這就更迷惑了。測試 app 顯示的準嗎,和系統看到的一樣嗎?

如果這句無效果,那麼 /toggleascii 分支看上去就只是改了 ascii_mode、並且少了 _EnableLanguageBar(isOpen); 的調用。那麼他是怎麼做到不禁用輸入法的呢?

我繼續追問,_IsKeyboardOpen() == FALSE 的時候,後續按鍵能不能發給 librime?這是比狀態顯示更重要的問題。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

測試 app 顯示的準嗎,和系統看到的一樣嗎?

当然准的,至少在win11 24h2里就是这样。

如果這句無效果,那麼 /toggleascii 分支看上去就只是改了 ascii_mode、並且少了 _EnableLanguageBar(isOpen); 的調用。那麼他是怎麼做到不禁用輸入法的呢?

所以就没有禁用输入法,只是改了输入法的 ascii 状态。

我繼續追問,_IsKeyboardOpen() == FALSE 的時候,後續按鍵能不能發給 librime?這是比狀態顯示更重要的問題。

能,除非设置为 /toggleime,具体逻辑看这里:

if ((_isToOpenClose && !_IsKeyboardOpen()) || _IsKeyboardDisabled()) {

@lotem
Copy link
Member

lotem commented Feb 20, 2025

謝謝。
原來禁用輸入法是這樣主動實現的。那理論上所有輸入法可以輕鬆繞過這個禁用狀態……

如果實際行爲不變的話,PR 值得考慮啊。

輸入法框架記了一個有用的狀態,可以同步給 rime;
可是 rime 的狀態有沒有同步給 keyboard open 呢?

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

可是 rime 的狀態有沒有同步給 keyboard open 呢?

这确实没有,之前也没有同步,所以有时候 ImTip 的状态显示才会异常,不过这跟 #1486 的原始问题无关,所以我没提。

真要修复也容易,在这里:

void WeaselTSF::_UpdateLanguageBar(weasel::Status stat) {

根据传入的 status,调用一下 _SetKeyboardOpen 就行了。

@lotem
Copy link
Member

lotem commented Feb 20, 2025

根据传入的 status,调用一下 _SetKeyboardOpen 就行了。

設置這些狀態如果系統沒有表現,最終只是讓輸入法自己遵守的話,無怪輸入法程序沒動力設置呢。

據說這些狀態CMD窗口會用到。

@fxliang
Copy link
Contributor

fxliang commented Feb 20, 2025

将代码拉下来编了试了在_SetKeyboardOpen前后加OutputDebugString调试信息跟踪,在这个回调里_SetKeyboardOpen确认无效可以删,另外 #1364 确认未被break。就差如果输入法方案如果初始化为ascii_mode的状态下第一次Ctrl+space响应不对的问题了@wzv5

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

就差如果输入法方案如果初始化为ascii_mode的状态下第一次Ctrl+space响应不对的问题了@wzv5

确认就这样了么?我可不想再返工了。。

可是 rime 的狀態有沒有同步給 keyboard open 呢?

要不要在这个 pr 里实现?当然我倾向于不要,这或许会牵扯到其他问题,先修好一个问题再说。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

看了下,还是在

void WeaselTSF::_UpdateLanguageBar(weasel::Status stat) {

这里同步键盘开关状态最佳,一次解决两个问题。粗略测试了下,没毛病。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

当我没说。。实测不行。。跟rime实时同步ascii状态还是先放着吧,先解决初始状态同步。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

@fxliang 现在应该没问题了,你再把把关。

@popyoung 一会 ci 编译出来后你也试试看。

@popyoung
Copy link

好的,是weasel-artifact-0.16.3.29.9c77c8d这个吧

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 20, 2025

好的,是weasel-artifact-0.16.3.29.9c77c8d这个吧

对的。

@popyoung
Copy link

简单试用了下,之前的问题都修正了。

@fxliang
Copy link
Contributor

fxliang commented Feb 21, 2025

试过基本可以了,就WeaselTSF/LanguageBar.cpp里修改那个if最好调整下可以让后面看起来清晰一点。
改完就可以合并了@wzv5

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 21, 2025

试过基本可以了,就WeaselTSF/LanguageBar.cpp里修改那个if最好调整下可以让后面看起来清晰一点。 改完就可以合并了@wzv5

感觉这样写 if 更符合下面的逻辑,不然阅读代码时需要在脑内反转一下。
反正经过编译器的优化,最终结果都一样的。

@wzv5
Copy link
Contributor Author

wzv5 commented Feb 21, 2025

那就优化一下,@fxliang 现在这样写如何?为了阅读方便。

@@ -416,7 +416,8 @@ void WeaselTSF::_UpdateLanguageBar(weasel::Status stat) {
else
flags &= (~TF_CONVERSIONMODE_FULLSHAPE);
_SetCompartmentDWORD(flags, GUID_COMPARTMENT_KEYBOARD_INPUTMODE_CONVERSION);

if (!_isToOpenClose && _IsKeyboardOpen() != (!stat.ascii_mode))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  if (!_isToOpenClose && (_IsKeyboardOpen() == stat.ascii_mode))

可能更清晰,另外可以考虑加一两行注释

@fxliang fxliang merged commit ea49aa1 into rime:master Feb 22, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Claunch激活窗口后有时候会修改中英文状态
4 participants