EM_SETSEL меняет параметры - PullRequest
3 голосов
/ 04 января 2012

Я использую сообщение EM_SETSEL для выбора текста в редактировании. Мне нужно выделить какой-то текст от конца до середины, чтобы позиция каретки находилась посередине текста. Документация MSDN гласит следующее:

Начальное значение может быть больше конечного значения. Нижнее из двух значений указывает положение символа первого символа в выделении. Более высокое значение указывает положение первого символа за пределами выделения.

Начальное значение является точкой якорь выбора, а конечное значение является активным концом. Если пользователь использует клавишу SHIFT для настройки размера выделения, активный конец может двигаться, но точка привязки остается прежней.

Но кажется, что меньшее значение всегда становится якорем, например, Я не могу добиться желаемого поведения.

Пример кода (где "parent" - CWnd *):

TRACE("EM_SETSEL(%d, %d)\n", pos1, pos2);
parent->SendMessage(EM_SETSEL, pos1, pos2);
parent->SendMessage(EM_GETSEL, (WPARAM)&pos1, (LPARAM)&pos2);
TRACE("EM_GETSEL(%d, %d)\n", pos1, pos2);

производит вывод:

EM_SETSEL(5, 1)
EM_GETSEL(1, 5)

Есть ли другой способ получить желаемый выбор?

Ответы [ 2 ]

0 голосов
/ 28 сентября 2017

Относительно EM_GETSEL / EM_SETSEL:

  • EM_GETSEL извлекает левые / правые позиции
  • EM_SETSEL устанавливает якорные / активные позиции

EM_SETSEL использует якорные / активные позиции, что позволяет легко размещать каретку слева / справа от выделения, поэтому я не уверен, почему в другом ответе использовался кладж.

EM_GETSEL - неудобное сообщение окна, для которого кладжявляется необходимым.Этот кладж временно меняет выделение на 0 символов, чтобы восстановить активную позицию, однако, когда я его использовал, я не увидел видимых изменений.

Для извлечения якорных / активных позиций:

  • используйте EM_GETSEL для извлечения левых / правых позиций
  • используйте EM_SETSEL, чтобы временно установить выбор в 0 символов, оставляя каретку в активной позиции
  • используйте EM_GETSEL для извлеченияактивная позиция
  • использовать EM_SETSEL для восстановления исходного выбора

Некоторые примеры кода AutoHotkey для установки выбора:

q:: ;Notepad - set active position (caret) at right
PostMessage, 0xB1, 5, 10, Edit1, A ;EM_SETSEL := 0xB1
return

w:: ;Notepad - set active position (caret) at left
PostMessage, 0xB1, 10, 5, Edit1, A ;EM_SETSEL := 0xB1
return

Некоторые примеры функций AutoHotkey для получения /установка выбора:

JEE_EditGetRange(hCtl, ByRef vPos1, ByRef vPos2)
{
    VarSetCapacity(vPos1, 4), VarSetCapacity(vPos2, 4)
    SendMessage, 0xB0, % &vPos1, % &vPos2,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0 ;(left, right)
    vPos1 := NumGet(&vPos1, 0, "UInt"), vPos2 := NumGet(&vPos2, 0, "UInt")
}

;==================================================

JEE_EditSetRange(hCtl, vPos1, vPos2, vDoScroll:=0)
{
    SendMessage, 0xB1, % vPos1, % vPos2,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1 ;(anchor, active)
    if vDoScroll
        SendMessage, 0xB7, 0, 0,, % "ahk_id " hCtl ;EM_SCROLLCARET := 0xB7
}

;==================================================

;note: although this involves deselecting and selecting it seems to happen invisibly
JEE_EditGetRangeAnchorActive(hCtl, ByRef vPos1, ByRef vPos2)
{
    ;get selection
    VarSetCapacity(vPos1, 4), VarSetCapacity(vPos2, 4)
    SendMessage, 0xB0, % &vPos1, % &vPos2,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
    vPos1 := NumGet(&vPos1, 0, "UInt"), vPos2 := NumGet(&vPos2, 0, "UInt")
    if (vPos1 = vPos2)
        return
    vPos1X := vPos1, vPos2X := vPos2

    ;set selection to 0 characters and get active position
    SendMessage, 0xB1, -1, 0,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1
    VarSetCapacity(vPos2, 4)
    SendMessage, 0xB0, % &vPos2, 0,, % "ahk_id " hCtl ;EM_GETSEL := 0xB0
    vPos2 := NumGet(&vPos2, 0, "UInt")

    ;restore selection
    vPos1 := (vPos2 = vPos2X) ? vPos1X : vPos2X
    SendMessage, 0xB1, % vPos1, % vPos2,, % "ahk_id " hCtl ;EM_SETSEL := 0xB1 ;(anchor, active)
}

ССЫЛКИ:

Функции выше, которые я первоначально разместил на форумах AutoHotkey:
КОМАНДЫ GUI: ПОЛНАЯ ПЕРЕСМОТРЕНИЕ - Сообщество AutoHotkey
https://autohotkey.com/boards/viewtopic.php?f=5&t=25893&p=138292#p138292

0 голосов
/ 01 декабря 2014

Это можно сделать с помощью довольно уродливого клуджа.В принципе, нет никакого способа сказать элементу управления выделять текст и оставлять курсор слева, но вы можете заставить элемент управления делать это сам, имитируя нажатия клавиш.

void EditSelSel(HWND hwndEdit, int iFirst, int iSecond)
{
    if (iFirst <= iSecond)
        SendMessage(hwndEdit, EM_SETSEL, iFirst, iSecond);
    else
    {
        SendMessage(hwndEdit, EM_SETSEL, iFirst, iFirst);

        BYTE bState[256]{}, bNewState[256]{};
        if (GetKeyboardState(bState))
        {
            memcpy(bNewState, bState, sizeof(bNewState));
            bNewState[VK_SHIFT] |= 128;
            if (SetKeyboardState(bNewState))
            {
                int i = iFirst - iSecond;
                while (i-- > 0)
                {
                    SendMessage(hwndEdit, WM_KEYDOWN, VK_LEFT, 0);
                }
                SendMessage(hwndEdit, WM_KEYUP, VK_LEFT, 0);
                SetKeyboardState(bState);
            }
        }
    }
}

Это работает путем позиционирования курсора направый конец диапазона выбора.Затем мы используем SetKeyboardState, чтобы заставить управление думать, что клавиша Shift удерживается нажатой, а затем имитировать достаточно нажатий клавиши Влево для перемещения диапазона в левый конец.

Ужасно, но это работает, так что, надеюсь, кто-то найдет это полезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...