rime / weasel

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

Windows 11 edge/Chrome中打字总是从光标位置左边飞入输入框 #1327

Closed changzaicl closed 4 days ago

changzaicl commented 1 week ago

PixPin_2024-07-05_15-16-31

请问是否有办法解决。谢谢!

changzaicl commented 1 week ago

刚在没有外接显示器的情况下,又测试了。 第一次打,还是“飞入”感觉。输入一半,删除编码区,那么就没有“飞入”的感觉(应该是找到了输入点)。

liangzhi52 commented 1 week ago

这个问题确实存在,在 chrome 内核的浏览器或其他产品中会有这个问题。 经过调试发现,这个现象跟 void WeaselPanel::MoveTo(RECT const& rc) 函数有关,当在 chrome 的 Input 框中打字时 rc.left 的值 不准确。

原因分析

中文输入状态下,按下字符后,每次按键 WeaselPanel::MoveTo 函数都会被调用多次(大概是7-9次样子),此时 rc.left 的值是不稳定的(部分值比实际位置 小,通常出现在第 2-4 次),会导致楼主提到的现象。 坐标变化 上图中红色字体,3个值就是导致这个问题的原因。

临时解决方案

为了解决这个问题,我用了临时的解决方案(WIN11下测试正常),应该不是最佳解决方案 这个方案的思路就是取 m_composing_count == 5 时候的值(跳过不稳定的值),避免闪烁。 以下的程序在解决闪烁问题的基础上,也实现了候选框不随着光标移动。

void WeaselPanel::MoveTo(RECT const& rc) {
  if (!m_layout)
    return;  // avoid handling nullptr in _RepositionWindow
  m_redraw_by_monitor_change = false;

  if (m_status.composing) {
    ++m_composing_count;
  } else {
    m_composing_count = 0;
    m_composing_moved = false;
  }

  if (1 == m_composing_count) {
    m_composing_count1_pos = rc.left;
  }

  // if (5 == m_composing_count) {
  //  m_composing_count5_pos = rc.left;
  //}

  const int x_offeset = 2;

  // if ascii_tip_follow_cursor set, move tip icon to mouse cursor
  if (m_style.ascii_tip_follow_cursor && m_ctx.empty() &&
      (!m_status.composing) && m_layout->ShouldDisplayStatusIcon()) {
    // ascii icon follow cursor
    POINT p;
    ::GetCursorPos(&p);
    RECT irc{p.x - STATUS_ICON_SIZE, p.y - STATUS_ICON_SIZE, p.x, p.y};
    m_inputPos = irc;
    _RepositionWindow(true);
    RedrawWindow();
  } else if (!m_status.composing ||  // 除这个条件外,其他条件都是在 composing
                                     // 状态下执行的
             ((abs(rc.left - m_composing_count1_pos) != x_offeset ||   // wps
               abs(rc.left - m_composing_count1_pos) != x_offeset) &&  // chrome
              (5 == m_composing_count &&
               !m_composing_moved)) ||  // m_composing_count == 5
                                        // 的时候位置是准确的
             abs(rc.bottom - m_inputPos.bottom) != 6 ||
             (abs(rc.bottom - m_inputPos.bottom) == 6 &&
              rc.left < m_inputPos.left && m_composing_count > 5)) {
    // in some apps like word 2021, with inline_preedit set,
    // bottom of rc would flicker 1 px or 2, make the candidate flickering

    if (m_status.composing && !m_composing_moved) {
      m_composing_moved = true;
    }

    m_inputPos = rc;
    m_inputPos.OffsetRect(-x_offeset, 6);
    // buffer current m_istorepos status
    bool m_istorepos_buf = m_istorepos;
    // with parameter to avoid vertical flicker
    _RepositionWindow(true);
    // m_istorepos status changed by _RepositionWindow, or tips to show,
    // redrawing is required
    if (m_istorepos != m_istorepos_buf || !m_ctx.aux.empty() ||
        m_layout->ShouldDisplayStatusIcon() || m_redraw_by_monitor_change)
      RedrawWindow();
  }
}

其他说明

而在 【记事本】等程序中,则不会出现这种情况。

changzaicl commented 1 week ago

谢谢!请问您这个如何使用,我也测试一下。再次感谢!

liangzhi52 commented 1 week ago

谢谢!请问您这个如何使用,我也测试一下。再次感谢!

WeaselUI.zip 是 WeaselPanel.cpp WeaselPanel.h ,可以自己编译 win11下没有问题,win10 没有充分测试 WeaselUI.zip

weasel-1.0.8.2-installer.zip 是编译好的完整版: weasel-1.0.8.2-installer.zip

changzaicl commented 1 week ago

的确好了很多。暂时先用着,等着fxliang大大更新。谢谢!

liangzhi52 commented 1 week ago

的确好了很多。暂时先用着,等着fxliang大大更新。谢谢!

不客气

fxliang commented 6 days ago

不是很确定,是不是和异步编辑相关联。在ui里过滤其实可能不是最好的办法

考虑试下在这个位置考虑处理一下可能会更加合适

https://github.com/rime/weasel/blob/master/WeaselTSF/Composition.cpp#L388

changzaicl commented 5 days ago

大佬们加油!这已经超出了生物专业出身的能力范围,但测试是可行的。