Page 1 of 1

Как получить ссылку при наведении на нё мышью

Posted: Wed Dec 20, 2017 12:20 pm
by Andrey_A_A
Подскажите, есть ли возможность получить внешним приложением ссылку, на которую наведён курсор мыши?
В частности, интересует реализация на Autoit
В простом Edit находится позиция через _GUICtrlEdit_CharFromPos
В простом RichEdit через _GUICtrlRichEdit_GetCharPosFromXY
в AkelPad ни то и ни другое не работает...

Posted: Wed Dec 20, 2017 7:02 pm
by KDJ
Andrey_A_A

In AkelEdit you can use AEM_CHARFROMPOS or EM_CHARFROMPOS message.
Description and example of AEM_CHARFROMPOS are in AkelEdit.h.
About EM_CHARFROMPOS you can read here: https://msdn.microsoft.com/en-us/librar ... s.85).aspx

Posted: Thu Dec 21, 2017 4:55 am
by Andrey_A_A
KDJ, у меня есть функция получения ссылки из AkelPad

Code: Select all

' Функция получения ссылки под курсором или позиции
 ' cpCnt: 0 - ссылка, 1 - начало позиции, 2 - конец позиции 3 - массив со ссылкой, начальной позиции и конечной
Function GetLinkUnderCaret(cpCnt)
  With AkelPad Res = ""
    If vbX64 Then : cc = 24 : vv = 48 : Else : cc = 12 : vv = 24 : End If
    lpCaret = .MemAlloc(cc)
    If Len(lpCaret) > 0 Then
      hWE = .GetEditWnd : .SendMessage hWE, 3130, 5, lpCaret : lpRange = .MemAlloc(vv)
      Call .SetClipboardText(hWE)
      If Len(lpRange) > 0 And .SendMessage(hWE, 3149, lpCaret, lpRange) Then
        cpMin = .SendMessage(hWE, 3136, 0, lpRange)
        cpMax = .SendMessage(hWE, 3136, 0, lpRange + cc)
        Select Case cpCnt
          Case 0 Res = .GetTextRange(cpMin, cpMax)
          Case 1 Res = cpMin
          Case 2 Res = cpMax
          Case 3 Res = Array(.GetTextRange(cpMin, cpMax), cpMin, cpMax)
        End Select
      End If
      .MemFree(lpRange)
    End If
    .MemFree(lpCaret)
  End With : GetLinkUnderCaret = Res
End Function
Мне нужна функция для получение позиции (слова/ссылки), когда я передаю ей координаты мыши X, Y

В RichEdit в Autoit есть функции - они нормально работают в RichEdit, в AkelPad нет - у него свой класс...
Хотелось бы разобраться, что где подправить...

Code: Select all

Func _GUICtrlRichEdit_GetCharPosFromXY($hWnd, $iX, $iY)
	Local $aiRect = _GUICtrlRichEdit_GetRECT($hWnd)
	If $iX < $aiRect[0] Or $iX > $aiRect[2] Or $iY < $aiRect[1] Or $iY > $aiRect[3] Then Return -1
	Local $tPointL = DllStructCreate("LONG x; LONG y;")
	DllStructSetData($tPointL, 1, $iX)
	DllStructSetData($tPointL, 2, $iY)
	Local $iRet = _SendMessage($hWnd, $EM_CHARFROMPOS, 0, $tPointL, 0, "wparam", "struct*")
	If Not $iRet Then Return SetError(-1, 0, 0)
	Return $iRet
EndFunc

Func _GUICtrlRichEdit_GetRECT($hWnd)
	Local $tRECT = DllStructCreate($tagRECT)
	_SendMessage($hWnd, $EM_GETRECT, 0, $tRECT, 0, "wparam", "struct*")
	Local $aiRect[4]
	$aiRect[0] = DllStructGetData($tRECT, "Left")
	$aiRect[1] = DllStructGetData($tRECT, "Top")
	$aiRect[2] = DllStructGetData($tRECT, "Right")
	$aiRect[3] = DllStructGetData($tRECT, "Bottom")
	Return $aiRect
EndFunc
Кстати, эта функция возвращает номер 1-й видимой строки и не важно какие X и Y заданы...
-----------
Для обычного Edit достаточно

Code: Select all

Func _GUICtrlEdit_CharFromPos($hWnd, $iX, $iY)
	If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
	Local $aReturn[2]
	Local $iRet = _SendMessage($hWnd, $EM_CHARFROMPOS, 0, _WinAPI_MakeLong($iX, $iY))
	$aReturn[0] = _WinAPI_LoWord($iRet)
	$aReturn[1] = _WinAPI_HiWord($iRet)
	Return $aReturn
EndFunc

Posted: Thu Dec 21, 2017 7:05 pm
by KDJ
Andrey_A_A

In JScript:

Code: Select all

WScript.Echo("AEM_CHARFROMPOS: " + AEM_CHARFROMPOS() + "\n" + "EM_CHARFROMPOS: " + EM_CHARFROMPOS());

function AEM_CHARFROMPOS()
{
  var oSys     = AkelPad.SystemFunction();
  var lpPoint  = AkelPad.MemAlloc(8 /*sizeof(POINT)*/);
  var lpIndex  = AkelPad.MemAlloc(_X64 ? 24 : 12 /*sizeof(AECHARINDEX)*/);
  var hWndEdit = AkelPad.GetEditWnd();
  var nOffset;

  oSys.Call("User32::GetCursorPos", lpPoint);
  oSys.Call("User32::ScreenToClient", hWndEdit, lpPoint);

  if (AkelPad.SendMessage(hWndEdit, 3175 /*AEM_CHARFROMPOS*/, lpPoint, lpIndex) == 0 /*AEPC_ERROR*/)
    nOffset = -1;
  else
    nOffset = AkelPad.SendMessage(hWndEdit, 3136 /*AEM_INDEXTORICHOFFSET*/, 0, lpIndex);

  AkelPad.MemFree(lpPoint);
  AkelPad.MemFree(lpIndex);

  return nOffset;
}

function EM_CHARFROMPOS()
{
  var oSys     = AkelPad.SystemFunction();
  var lpPoint  = AkelPad.MemAlloc(8 /*sizeof(POINT)*/);
  var hWndEdit = AkelPad.GetEditWnd();
  var nOffset;

  oSys.Call("User32::GetCursorPos", lpPoint);
  oSys.Call("User32::ScreenToClient", hWndEdit, lpPoint);

  nOffset = AkelPad.SendMessage(hWndEdit, 0x00D7 /*EM_CHARFROMPOS*/, 0, lpPoint);

  AkelPad.MemFree(lpPoint);

  return nOffset;
}

Posted: Fri Dec 22, 2017 6:50 am
by Andrey_A_A
KDJ, спасибо, в AkelPad это работает, но к сожалению при внешнем вызове результата нет. Надеюсь найдётся решение... Может кто знает как это выглядет на Autoit

Posted: Fri Dec 22, 2017 7:58 pm
by KDJ
Andrey_A_A wrote:

Code: Select all

Func _GUICtrlRichEdit_GetCharPosFromXY($hWnd, $iX, $iY)
	Local $aiRect = _GUICtrlRichEdit_GetRECT($hWnd)
	If $iX < $aiRect[0] Or $iX > $aiRect[2] Or $iY < $aiRect[1] Or $iY > $aiRect[3] Then Return -1
	Local $tPointL = DllStructCreate("LONG x; LONG y;")
	DllStructSetData($tPointL, 1, $iX)
	DllStructSetData($tPointL, 2, $iY)
	Local $iRet = _SendMessage($hWnd, $EM_CHARFROMPOS, 0, $tPointL, 0, "wparam", "struct*")
	If Not $iRet Then Return SetError(-1, 0, 0)
	Return $iRet
EndFunc
I do not know AutoIt but it seems to me that this is the solution.
You just have to pass to this function the handle to AkelEdit control ($hWnd).
You need to find the handle to this control.
Default class name for AkelEdit is "AkelEditW".
If you set in AkelPad the manual parameter RichEditClass to 1, class name will be "RichEdit20W".