[BUG]: 中文输入法候选字位置始终处于左上角,未跟随输入框光标焦点处
Describe the bug 【Bug描述】
在Linux(UOS)平台下,在网页输入框里输入中文内容时,输入法的候选字窗口始终处于屏幕左上角,测试本地页面和网络页面均是如此。
另外测试了cefsample程序,是正常现象,所以可排除CEF问题。
To Reproduce 【复现步骤】
- 启动程序,在输入框中输入中文
- 输入法候选字窗口始终处于左上角
Expected behavior 【正确的预期行为】
候选字窗口跟随光标焦点
Screenshots 【截图】
Environment 【BUG产生的环境】
- OSR/NCW Mode: OSR
- OS & Version: Linux
- Qt Version: Qt 5.15.2
- CEF Version: 113.3.5+g0b33855+chromium-113.0.5672.129
Additional context 【更多额外信息】
...
使用Ubuntu是正常的,因为使用的ibus框架,Deepin/UOS使用的是fctix。
在调试过程中,当输入法为中文时,按下字母按键时,Ubuntu可以进入QCefView::keyPressEvent(QKeyEvent* event)事件,并发送key char event。但是Deepin/UOS则没有进入QCefView::keyPressEvent(QKeyEvent* event),不确定是否是这里的问题
同样的情况:https://github.com/CefView/QCefView/issues/436
这个问题是 OSR 之后引起的 cefsimple 不是 osr, 不过我测试了 CEF136 cefclient OSR 模式下连中文都无法输入了。 PS:注意官方示例的 SanityCheckWindowConfig 方法会重新修正 OSR 的值,开启OSR时必须开启 use_alloy_style。
补充:windows + OSR + 搜狗位置也不对,微软拼音正常。
先别试OSR了,感觉OSR模式快残了。无论是software还是hardware rendering,都有一些问题,还在改进中,但是不保证能彻底解决。
这个问题的原因是输入法正常情况有一个预先上屏功能,但是某些输入法没有提供,所以有这个问题,可以尝试虚拟上屏,就是把上次输入的内容作为预上屏内容发给浏览器,效果很好,代码如下;
void
QCefViewPrivate::onViewInputMethodEvent(QInputMethodEvent* event)
{
if (isOSRModeEnabled_) {
// OSR mode
if (!pCefBrowser_)
return;
auto composingText = event->preeditString();
auto composedText = event->commitString();
if (!composedText.isEmpty()) {
CefCompositionUnderline underline;
underline.background_color = 0;
underline.range = { 0, static_cast<decltype(CefRange::to)>(composedText.length()) };
CefRange selectionRange;
for (auto& attr : event->attributes()) {
switch (attr.type) {
case QInputMethodEvent::TextFormat:
break;
case QInputMethodEvent::Cursor:
selectionRange.Set(attr.start, attr.start);
break;
case QInputMethodEvent::Language:
case QInputMethodEvent::Ruby:
case QInputMethodEvent::Selection:
break;
default:
break;
}
}
//由于搜狗输入法没有提供预上屏功能,再次模拟预生屏功能
pCefBrowser_->GetHost()->ImeSetComposition(
composedText.toStdString(), { underline }, CefRange(UINT32_MAX, UINT32_MAX), selectionRange);
pCefBrowser_->GetHost()->ImeCommitText(composedText.toStdString(), CefRange(UINT32_MAX, UINT32_MAX), 0);
} else if (!composingText.isEmpty()) {
CefCompositionUnderline underline;
underline.background_color = 0;
underline.range = { 0, static_cast<decltype(CefRange::to)>(composingText.length()) };
CefRange selectionRange;
for (auto& attr : event->attributes()) {
switch (attr.type) {
case QInputMethodEvent::TextFormat:
break;
case QInputMethodEvent::Cursor:
selectionRange.Set(attr.start, attr.start);
break;
case QInputMethodEvent::Language:
case QInputMethodEvent::Ruby:
case QInputMethodEvent::Selection:
break;
default:
break;
}
}
pCefBrowser_->GetHost()->ImeSetComposition(
composingText.toStdString(), { underline }, CefRange(UINT32_MAX, UINT32_MAX), selectionRange);
} else {
pCefBrowser_->GetHost()->ImeCancelComposition();
}
}
}
@tishion @L-Super
这个问题的原因是输入法正常情况有一个预先上屏功能,但是某些输入法没有提供,所以有这个问题,可以尝试虚拟上屏,就是把上次输入的内容作为预上屏内容发给浏览器,效果很好,代码如下;
void QCefViewPrivate::onViewInputMethodEvent(QInputMethodEvent* event) { if (isOSRModeEnabled_) { // OSR mode if (!pCefBrowser_) return;
auto composingText = event->preeditString(); auto composedText = event->commitString(); if (!composedText.isEmpty()) { CefCompositionUnderline underline; underline.background_color = 0; underline.range = { 0, static_cast<decltype(CefRange::to)>(composedText.length()) }; CefRange selectionRange; for (auto& attr : event->attributes()) { switch (attr.type) { case QInputMethodEvent::TextFormat: break; case QInputMethodEvent::Cursor: selectionRange.Set(attr.start, attr.start); break; case QInputMethodEvent::Language: case QInputMethodEvent::Ruby: case QInputMethodEvent::Selection: break; default: break; } } //由于搜狗输入法没有提供预上屏功能,再次模拟预生屏功能 pCefBrowser_->GetHost()->ImeSetComposition( composedText.toStdString(), { underline }, CefRange(UINT32_MAX, UINT32_MAX), selectionRange); pCefBrowser_->GetHost()->ImeCommitText(composedText.toStdString(), CefRange(UINT32_MAX, UINT32_MAX), 0); } else if (!composingText.isEmpty()) { CefCompositionUnderline underline; underline.background_color = 0; underline.range = { 0, static_cast<decltype(CefRange::to)>(composingText.length()) }; CefRange selectionRange; for (auto& attr : event->attributes()) { switch (attr.type) { case QInputMethodEvent::TextFormat: break; case QInputMethodEvent::Cursor: selectionRange.Set(attr.start, attr.start); break; case QInputMethodEvent::Language: case QInputMethodEvent::Ruby: case QInputMethodEvent::Selection: break; default: break; } } pCefBrowser_->GetHost()->ImeSetComposition( composingText.toStdString(), { underline }, CefRange(UINT32_MAX, UINT32_MAX), selectionRange); } else { pCefBrowser_->GetHost()->ImeCancelComposition(); }
历史有一些久远,印象中尝试过,有时间再试试
好,原因就是cef浏览器在离屏渲染模式下依赖输入法的预先上屏功能来定位光标的位置;而搜狗输入法没有提供该功能,导致问题产生;而自带demo不是离屏渲染模式下所以没问题。
@oufengfang 可以提交一个PR吗?
好,我提交试试哈