简体   繁体   English

EM_SETSEL交换参数

[英]EM_SETSEL swaps parameters

I use EM_SETSEL message to select text in edit control. 我使用EM_SETSEL消息在编辑控件中选择文本。 I need to select some text from the end to the middle, so that caret position is in the middle of the text. 我需要从末尾到中间选择一些文本,以便插入位置位于文本的中间。 MSDN documentation states the following: MSDN文档说明以下内容:

The start value can be greater than the end value. 起始值可以大于结束值。 The lower of the two values specifies the character position of the first character in the selection. 两个值中的较低者指定选择中第一个字符的字符位置。 The higher value specifies the position of the first character beyond the selection. 较高的值指定超出选择范围的第一个字符的位置。

The start value is the anchor point of the selection, and the end value is the active end. 起始值是选择的锚点,结束值是活动结束。 If the user uses the SHIFT key to adjust the size of the selection, the active end can move but the anchor point remains the same. 如果用户使用SHIFT键调整选择的大小,则活动端可以移动但锚点保持不变。

But it seems that lesser value always becomes an anchor, eg I cannot achieve the desired behaviour. 但似乎较小的价值总是成为一个锚点,例如我无法达到预期的行为。

Code sample (where "parent" is CWnd*): 代码示例(其中“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);

produces the output: 产生输出:

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

Is there another way to get the desired selection? 有没有其他方法可以获得所需的选择?

This can be done via a rather ugly kludge. 这可以通过一个相当丑陋的kludge来完成。 Basically there's no way to tell the control to select text and leave the cursor at the left, but you can make the control do it itself by simulating key presses. 基本上没有办法告诉控件选择文本并将光标留在左侧,但您可以通过模拟按键使控件自行完成。

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);
            }
        }
    }
}

This works by positioning the cursor at the right end of the selection range. 这可以通过将光标定位在选择范围的右端来实现。 We then use SetKeyboardState to trick the control into thinking the Shift key is held down, and then simulate enough Left key presses to move the range to the left end. 然后我们使用SetKeyboardState来诱使控件认为Shift键被按下,然后模拟足够的左键按下以将范围移动到左端。

Ugly, but it works, so hopefully someone finds it useful. 丑陋,但它有效,所以希望有人发现它很有用。

Regarding EM_GETSEL/EM_SETSEL: 关于EM_GETSEL / EM_SETSEL:

  • EM_GETSEL retrieves left/right positions EM_GETSEL检索左/右位置
  • EM_SETSEL sets anchor/active positions EM_SETSEL设置锚点/活动位置

EM_SETSEL uses anchor/active positions, allowing you to easily place the caret at the left/right of the selection, so I'm not sure why a kludge was used in the other answer. EM_SETSEL使用锚点/活动位置,允许您轻松地将插入符号放在选择的左侧/右侧,因此我不确定为什么在另一个答案中使用了kludge。

EM_GETSEL is the awkward window message, for which a kludge is necessary. EM_GETSEL是一个尴尬的窗口消息,需要一个kludge。 This kludge temporarily changes the selection to 0 characters, in order to retrieve the active position, however, when I've used it I haven't seen any visible change. 此kludge暂时将选择更改为0个字符,以便检索活动位置,但是,当我使用它时,我没有看到任何明显的变化。

To retrieve anchor/active positions: 要检索锚点/活动位置:

  • use EM_GETSEL to retrieve the left/right positions 使用EM_GETSEL检索左/右位置
  • use EM_SETSEL to temporarily set the selection to 0 characters, leaving the caret at the active position 使用EM_SETSEL暂时将选择设置为0个字符,使插入符号处于活动位置
  • use EM_GETSEL to retrieve the active position 使用EM_GETSEL检索活动位置
  • use EM_SETSEL to restore the original selection 使用EM_SETSEL恢复原始选择

Some example AutoHotkey code for setting the selection: 一些示例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

Some example AutoHotkey functions for getting/setting the selection: 一些示例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)
}

LINKS: 链接:

The functions above that I originally posted at the AutoHotkey forums: 我最初在AutoHotkey论坛发布的上述功能:
GUI COMMANDS: COMPLETE RETHINK - AutoHotkey Community GUI命令:完整的RETHINK - AutoHotkey社区
https://autohotkey.com/boards/viewtopic.php?f=5&t=25893&p=138292#p138292 https://autohotkey.com/boards/viewtopic.php?f=5&t=25893&p=138292#p138292

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM