EM_EXGETSEL与文本选择顺序无关。如何确定所选文本中的插入位置?

时间:2013-08-23 00:50:52

标签: c++ winapi richedit-control

当我这样做时:

SendMessage(editControlHWND, EM_EXGETSEL, 0, (LPARAM)&charRange);

我得到所选的文字范围。但是,我想知道插入符号在这个选择中的位置,即最后,或者在开头。

即,用户选择了“向后”文本,就像从右向左拖动一样。

EM_EXGETSEL始终在cpMin中包含较小的数字,因此显然与选择顺序无关。

在这种情况下,我显然无法使用EM_EXGETSEL获取插入位置,因为已经选择了一大块东西。

有没有办法获得插入符号当前的个别位置(以便我可以将它与cpMin / cpMax进行比较)?或者,有没有办法确定插入符号在选定文本块中的位置?

修改

我解释为什么要这样做: 我以编程方式将文本插入到只读的RichEdit控件中,用户可以从中选择文本。但是,在最后添加文本时,必须将插入符号移到末尾并插入文本,这可能在选择了文本/用户当前正在选择文本时发生。

这是最后一个麻烦。我使用EM_EXGETSELEM_EXSETSEL来获取和设置在以编程方式输入文本之前和之后的所选文本。默认情况下,EM_EXGETSEL将始终将较小的数字放在cpMin中,这意味着如果用户当前正在向后选择文本(即从右到左),并且文本被添加到控件中,则位置为选择区域中的插入符号从开头到结尾都会发生变化,因为我将这些数字直接输入EM_EXSETSEL。我知道EM_EXSETSEL能够向后选择(我已使用cpMin中的较大数字和cpMax中较小的数字进行了测试,但EM_EXGETSEL不提供任何表示用户已向后选择文本。

因此,我需要知道插入符号位置,以便将其与cpMincpMax进行比较,以检查它是在选择的开头还是结尾,并采取相应的行动。

4 个答案:

答案 0 :(得分:1)

在调查同样的问题时,我刚看过这篇文章。

我能够通过跟踪EN_SELCHANGE通知的选择的更改并比较WM_LBUTTONUP的结果来解决。

答案 1 :(得分:0)

没有简单的方法可以做到这一点。 EM_GETSELEM_EXGETSEL返回当前选择的范围。只有在没有选择的情况下才会返回插入符号的位置。

请注意,插入符号不能 所选文本块 - 它始终位于结尾或开头。

您可以通过对控件进行子类化并使用EM_GETSEL在任何键或鼠标输入后查询和存储插入符的位置,相当容易地实现解决方案。 E.g。

LRESULT WINAPI EditControlSubclassProc(...)
{
    LRESULT lRes = CallWindowProc(...); // call original window procedure
    if ((uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST)
    ||  (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST))
    {
        DWORD dwStart, dwEnd;
        SendMessage(hWnd, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
        if (dwStart == dwEnd)
        {
            // no current selection, so simply store the position of the caret
            g_dwCaretPos = dwStart;
        }
    }
    return lRes;
}

通过这种方式,您将始终知道最后一次输入没有导致选择时插入符号的位置。然后,您可以将其与选择范围进行比较,以确定选择锚定在哪一端,因此知道插入符号位于另一端。

答案 2 :(得分:0)

似乎可以使用EM_LINEFROMCHAREM_LINEINDEX(WPARAM == -1)。

答案 3 :(得分:0)

我设法做到了这一点,虽然到达那里due to my lack of understanding on the concept of sub-classing有点复杂。 &GT;&LT;

我使用Spy ++来查看在选择文本时发送的消息。

这显然只是EM_GETPASSWORDCHAR消息。

所以我做了:

case EM_GETPASSWORDCHAR:
    {
        if(hwnd == editControlHwnd)
        {
            CHARRANGE tempCharRange;
            SendMessage(editControlHwnd, EM_EXGETSEL, 0, (LPARAM)&tempCharRange);
            SetSelectionDirection(tempCharRange.cpMin, tempCharRange.cpMax);
            return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
        }
    }

使用:

void SubWindow::SetSelectionDirection(int newCpMin, int newCpMax) //Set selectionDirection to false if selecting backwards, true if selecting forwards
{
    if((newCpMin != prevCpMin) && (newCpMax == prevCpMax))
        selectionDirection = false;
    else if((newCpMin == prevCpMin) && (newCpMax != prevCpMax))
        selectionDirection = true;

    prevCpMin = newCpMin;
    prevCpMax = newCpMax;
}

bool selectionDirection;int prevCpMin;int prevCpMax;是私有类成员变量。

这样,我将新选择的区域与先前选择的区域进行比较,以查看哪个区域已更改,哪个区域没有更改。

我不知道我在这里做什么是实际解决这个问题的一个坏方法,但如果有更好的方法来做到这一点,我还没有找到它。这就是为什么我发布这个作为答案的原因,以帮助其他人担任我的职位。