weasel icon indicating copy to clipboard operation
weasel copied to clipboard

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

Open changzaicl opened this issue 1 year ago • 9 comments

PixPin_2024-07-05_15-16-31

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

changzaicl avatar Jul 05 '24 07:07 changzaicl

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

changzaicl avatar Jul 05 '24 13:07 changzaicl

这个问题确实存在,在 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();
  }
}

其他说明

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

liangzhi52 avatar Jul 07 '24 11:07 liangzhi52

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

changzaicl avatar Jul 07 '24 11:07 changzaicl

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

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

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

liangzhi52 avatar Jul 07 '24 11:07 liangzhi52

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

changzaicl avatar Jul 07 '24 12:07 changzaicl

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

不客气

liangzhi52 avatar Jul 07 '24 12:07 liangzhi52

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

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

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

fxliang avatar Jul 08 '24 10:07 fxliang

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

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

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

这个问题应该是一直存在,我每天都会查看并下载安装最新的测试版。期望可以得到解决。

changzaicl avatar Jul 26 '24 12:07 changzaicl

嘿嘿,又来催促了。看着新的master,还是没解决这个,心里着急😄

changzaicl avatar Jul 30 '24 11:07 changzaicl

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

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

试着自己编译,会发生以下错误。 WeaselUI/WeaselPanel.h:149:7: error: code should be clang-formatted [-Wclang-format-violations] long ^ WeaselUI/WeaselPanel.h:150:25: error: code should be clang-formatted [-Wclang-format-violations] m_composing_count; // ��¼ composing ״̬�£����� MoveTo �����Ĵ��� WeaselUI/WeaselPanel.h:151:68: error: code should be clang-formatted [-Wclang-format-violations] long m_composing_count1_pos; // composing ״̬�� �� ��¼�״ν���

@liangzhi52 可否帮助解决一下。谢谢!

changzaicl avatar Aug 14 '24 01:08 changzaicl

烦请大佬们关注@fxliang

changzaicl avatar Sep 04 '24 15:09 changzaicl

烦请大佬们关注@fxliang

没有Windows 11机器,没有复现问题,关注不了。等风吧

fxliang avatar Sep 04 '24 16:09 fxliang

@liangzhi52 有办法解决吗?适配最新的master。 您之前发的,我编译后,总是出现错误:Please lint your code by "./clang-format.sh -n". 可有偿。感谢!

changzaicl avatar Sep 05 '24 00:09 changzaicl

@liangzhi52 有办法解决吗?适配最新的master。 您之前发的,我编译后,总是出现错误:Please lint your code by "./clang-format.sh -n". 可有偿。感谢!

安装llvm 18.1.6或更高版本,确保clang-format 在path中,在git-bash 中切换到代码目录,执行上面提示的命令,更新提交ci编译

fxliang avatar Sep 05 '24 01:09 fxliang

谢谢回复。我其实之前也默默的捐赠了 冰阔落🥤 :)

按照您的指导,跟着GPT的建议,竟然成功了。导师的每一句话都是有用的😄。谢谢!

changzaicl avatar Sep 05 '24 01:09 changzaicl

@wzv5 感觉这个问题是不是也与最近您的几个pr有关系。请帮助查看。谢谢!

changzaicl avatar Feb 23 '25 09:02 changzaicl

@wzv5 感觉这个问题是不是也与最近您的几个pr有关系。请帮助查看。谢谢!

呃,这么强迫症么。大概看起来像是 chrome 的问题? 我之前没注意过这个问题,刚测试了一下,确实存在,但频率挺低的,也不影响使用,我决定无视了。。

wzv5 avatar Feb 23 '25 09:02 wzv5

+1. 打字快的了,感觉非常明显。好像是会记录上次光标的位置

beyondkmp avatar Jul 03 '25 05:07 beyondkmp

这个问题确实存在,在 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();

} }

其他说明

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

这个真的能解决。

beyondkmp avatar Jul 03 '25 05:07 beyondkmp