[英]EM_SETSEL swaps parameters
我使用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)
有沒有其他方法可以獲得所需的選擇?
這可以通過一個相當丑陋的kludge來完成。 基本上沒有辦法告訴控件選擇文本並將光標留在左側,但您可以通過模擬按鍵使控件自行完成。
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鍵被按下,然后模擬足夠的左鍵按下以將范圍移動到左端。
丑陋,但它有效,所以希望有人發現它很有用。
關於EM_GETSEL / EM_SETSEL:
EM_SETSEL使用錨點/活動位置,允許您輕松地將插入符號放在選擇的左側/右側,因此我不確定為什么在另一個答案中使用了kludge。
EM_GETSEL是一個尷尬的窗口消息,需要一個kludge。 此kludge暫時將選擇更改為0個字符,以便檢索活動位置,但是,當我使用它時,我沒有看到任何明顯的變化。
要檢索錨點/活動位置:
一些示例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命令:完整的RETHINK - AutoHotkey社區
https://autohotkey.com/boards/viewtopic.php?f=5&t=25893&p=138292#p138292
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.