Когда я делаю:
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;
}
Таким образом, вы всегда будете знать, где каретка была в последний раз, когда ввод был не результат в выборе. Затем вы можете сравнить его с диапазоном выбора, чтобы определить, к какому концу был привязан выбор, и, следовательно, узнать, что каретка находится на другом конце.
Кажется, что EM_LINEFROMCHAR
а также EM_LINEINDEX
с (WPARAM == -1).
Мне удалось это сделать, хотя добраться туда было немного сложно из-за моего непонимания концепции подкласса. ><
Я использовал 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;
являются частными переменными члена класса.
Таким образом, я сравниваю новую выбранную область с ранее выбранной областью, чтобы увидеть, какой конец изменился, а какой нет.
Я не знаю, является ли то, что я здесь делаю, плохим способом на самом деле решить это, но если есть лучший способ сделать это, я не нашел это. Вот почему я публикую это как ответ в том случае, если это поможет кому-то другому на моей должности.