当我这样做时:
SendMessage(editControlHWND, EM_EXGETSEL, 0, (LPARAM)&charRange);
我得到了选定的文本范围。 但是,我想知道插入符号在此选择中的位置,即在末尾或开头。
即,用户是否选择了"向后"的文本,例如从右向左拖动。
EM_EXGETSEL
总是在cpMin
中拥有较小的数字,所以显然与选择顺序无关。
在这种情况下,我显然无法获得带有EM_EXGETSEL
进行比较的插入符号位置,因为已经选择了大量内容。
有没有办法获取插入符号的当前个人位置(以便我可以将其与 cpMin/cpMax 进行比较(? 或者,有没有办法确定插入符号在选定文本块中的位置?
编辑:
我对为什么要这样做的解释:我以编程方式将文本插入到用户可以从中选择文本的只读 RichEdit 控件中。 但是,当在末尾添加文本时,它必须将插入符号移动到末尾并插入文本,当已选择文本/用户当前正在选择文本时,可能会发生这种情况。
最后一个是麻烦。 我使用 EM_EXGETSEL
和 EM_EXSETSEL
在以编程方式输入文本之前和之后获取和设置所选文本。 默认情况下,EM_EXGETSEL
总是将较小的数字放在cpMin
中,这意味着如果用户当前正在向后(即从右到左(选择文本,并且将文本添加到控件中,则插入符号在选择区域中的位置会从开始到结束发生变化,因为我将这些数字直接输入到EM_EXSETSEL
中。 我知道EM_EXSETSEL
能够向后选择(我已经用cpMin
中的较大数字和cpMax
中较小的数字对此进行了测试(,但EM_EXGETSEL
并没有给出任何指示用户已向后选择文本。
因此,我需要知道插入符号位置以将其与cpMin
或cpMax
进行比较,以检查它是在选择的开头还是结尾,并采取相应的行动。
在研究同样的问题时刚刚遇到了这篇文章。
我能够通过跟踪EN_SELCHANGE通知的选择更改并比较WM_LBUTTONUP的结果来解决。
简单的方法可以做到这一点。 EM_GETSEL
和 EM_EXGETSEL
返回当前所选内容的范围。仅当没有选择时,它们才会返回插入符号的位置。
请注意,插入符号不能位于所选文本块中 - 它始终位于末尾或开头。
通过对控件进行子类化,并使用EM_GETSEL
在任何键或鼠标输入后查询和存储插入符号的位置,您可能可以相当容易地实现解决方案。 例如
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;
}
这样,您将始终知道上次输入未导致选择时插入符号的位置。然后,您可以将其与所选内容的范围进行比较,以确定所选内容锚定在哪一端,从而知道插入符号位于另一端。
似乎可以使用 (WPARAM == -1( 的EM_LINEFROMCHAR
和EM_LINEINDEX
。
我已经设法做到了这一点,尽管由于我对子类的概念缺乏了解,因此到达那里有点复杂。><</p>
我使用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;
是私有类成员变量。
这样,我将新选择的区域与先前选择的区域进行比较,以查看哪一端发生了变化,哪一端没有改变。
我不知道我在这里所做的是否是一种实际解决这个问题的糟糕方法,但如果有更好的方法来做到这一点,我还没有找到它。 这就是为什么我将其作为答案发布,以防它帮助其他人处于我的位置。