Page 1 of 2

Capturing Text from under your mouse cursor

Posted: Sun Aug 31, 2008 11:08 am
by fizban
A cool tool to capture the text under the mouse cursor. Originally created in VC++ by Nibu Babu Thomas

Code: Select all

; CaptureText
; Author: fizban (ported from a VC++ code of Nibu Babu Thomas)
; Original source: http://nibuthomas.wordpress.com/2008/08/15/capturing-text-from-under-your-mouse-cursor/
; Date:  31. August 2008
; OS: Windows 

EnableExplicit

;-Gadgets
Enumeration
  #txtValue
  #txtName
  #edValue
  #edName
  #imgCursor  
  #frmOptions
  #txtDrag
  #chkCopy
  #chkHide
  #chkAlwaysTop
EndEnumeration

;-Images
Enumeration
  #picHand
  #picNo
EndEnumeration

;-Prototypes
Prototype.l ProtoAccessibleObjectFromPoint(x.l,y.l,*ia,*var)
Global AccessibleObjectFromPoint.ProtoAccessibleObjectFromPoint
Define hdll.l

;Applications must initialize the COM library before they can call COM library functions 
CoInitialize_(0)
hdll=OpenLibrary(#PB_Any,"Oleacc.dll")
AccessibleObjectFromPoint=GetFunction(hdll,"AccessibleObjectFromPoint")

Procedure SetWindowTopMost(hWnd.l,TopMost.l)
  Define After.l
  If Topmost : After=#HWND_TOPMOST : Else : After=#HWND_NOTOPMOST :EndIf
  SetWindowPos_( hWnd, After, 0, 0, 0, 0, #SWP_NOMOVE | #SWP_NOSIZE )
EndProcedure

Procedure TextFromWindowPosition(*Name.String, *Value.String)  
  Define CursorPos.point,vt.VARIANT,*pIAcc.IAccessible,pName.l,len.l
  GetCursorPos_(@CursorPos) 
  If AccessibleObjectFromPoint(CursorPos\x,CursorPos\y,@*pIAcc,@vt)=#S_OK
    *Name\s=""
    If *pIAcc\get_accName(vt, @pName) = #S_OK 
      len = SysStringLen_(pName)
      *Name\s = Space(len) 
      WideCharToMultiByte_(#CP_ACP, 0,pName, -1, @*Name\s, len, 0, 0)    
      SysFreeString_(pName)
    EndIf
    *Value\s=""
    If *pIAcc\get_accValue(vt, @pName) = #S_OK 
      len = SysStringLen_(pName)
      *Value\s = Space(len) 
      WideCharToMultiByte_(#CP_ACP, 0,pName, -1, @*Value\s, len, 0, 0)    
      SysFreeString_(pName)
    EndIf
    *pIAcc\Release() 
  EndIf
  ProcedureReturn #True
EndProcedure  

;-Main
Define dragging.b,Btn.l,ev.l,hdc.l,PositionBeforeMove.Point
Define name.string,value.string,SystemPath.s
Define handcursor   = LoadCursor_(0,#IDC_HAND) 
Define normalcursor = LoadCursor_(0,#IDC_ARROW) 
Define nocursor = LoadCursor_(0,#IDC_NO) 


If OpenWindow(0, 0, 0, 540, 408, "Capture text", #PB_Window_SystemMenu | #PB_Window_ScreenCentered| #PB_Window_MinimizeGadget) And CreateGadgetList(WindowID(0)) 
  CreateGadgetList(WindowID(0))
  TextGadget(#txtName,14,14,46,16,"Name:")
  EditorGadget(#edName, 14, 30, 516, 110) 
  TextGadget(#txtValue,14,148,44,16,"Value:")
  EditorGadget(#edValue, 14, 164, 516, 160)
  CreateImage(#picHand,40,40)
  ;Image Gadgets do not properly handle directly monochrome icons. So we use an image to draw the icon
  ;see http://www.purebasic.fr/english/viewtopic.php?t=33943
  hdc=StartDrawing(ImageOutput(#picHand))
    Box(0,0,40,40,GetSysColor_(#COLOR_3DFACE))
    DrawImage (handcursor,0,0)
  StopDrawing()
  CreateImage(#picNo,40,40)
  hdc=StartDrawing(ImageOutput(#picNo))
    Box(0,0,40,40,GetSysColor_(#COLOR_3DFACE))
    DrawImage (nocursor,0,0)
  StopDrawing()
  ImageGadget(#imgCursor,140,334,40,40,ImageID(#picHand))
  TextGadget(#txtDrag,54,346,80,40,"Drag me around:")
  Frame3DGadget(#frmOptions,38,324,460,76,"")
  CheckBoxGadget(#chkCopy,240,336,240,20,"&Copy to clipboard on mouse up")
  CheckBoxGadget(#chkHide,240,356,240,20,"Hide window on drag")
  CheckBoxGadget(#chkAlwaysTop,240,376,240,20,"Always on top")
  ;Set the icon for the window using one of the standard icons
  SystemPath=Space(255) 
  GetSystemDirectory_(SystemPath,255) 
  SendMessage_(WindowID(0),#WM_SETICON,#False,ExtractIcon_(0,SystemPath+"\shell32.dll",73))
;--Main loop
  Repeat 
  Ev = WaitWindowEvent() 
    Select Ev
      Case #PB_Event_Gadget 
        Select EventGadget() 
          Case #imgCursor
            If EventType()=#PB_EventType_LeftClick 
              SetCapture_(WindowID(0))
              SetCursor_(handcursor)
              SetGadgetState(#imgCursor,ImageID(#picNo))
              dragging=#True
              If GetGadgetState(#chkHide) 
                PositionBeforeMove\x=WindowX(0)
                PositionBeforeMove\y=WindowY(0)
                ExamineDesktops()
                ResizeWindow(0,DesktopWidth(0),DesktopHeight(0),#PB_Ignore ,#PB_Ignore )
              EndIf
            EndIf
          Case #chkAlwaysTop
            SetWindowTopMost(WindowID(0),GetGadgetState(#chkAlwaysTop))
        EndSelect
      Case #WM_MOUSEMOVE 
        If dragging=#True
          TextFromWindowPosition(@name,@value)
          SetGadgetText(#edName,name\s )
          SetGadgetText(#edValue,value\s)
        EndIf
      Case  #WM_LBUTTONUP 
        If dragging=#True
          ReleaseCapture_()
          SetCursor_(normalcursor)
          SetGadgetState(#imgCursor,ImageID(#picHand))
          dragging=#False
          If GetGadgetState(#chkCopy)
            SetClipboardText(name\s + #CRLF$ + value\s)
          EndIf
        EndIf
        If GetGadgetState(#chkHide) 
          ResizeWindow(0,PositionBeforeMove\x,PositionBeforeMove\y,#PB_Ignore ,#PB_Ignore )
        EndIf      
    EndSelect
  Until Ev = #PB_Event_CloseWindow 
EndIf
CoUninitialize_() 
CloseLibrary(hdll) 

Posted: Sun Aug 31, 2008 11:12 am
by Derek
That works really well, thanks for sharing.

Posted: Sun Aug 31, 2008 11:22 am
by srod
Very impressive. 8)

Doesn't work though for text in the IDE main window; the scintilla control.

Re: Capturing Text from under your mouse cursor

Posted: Sun Aug 31, 2008 12:31 pm
by PB
> Applications must initialize the COM library before they can call COM library functions
> CoInitialize_(0)

Is this really necessary? Seems to work fine without it? Good code, BTW. :)

Re: Capturing Text from under your mouse cursor

Posted: Sun Aug 31, 2008 12:43 pm
by freak
PB wrote:> Applications must initialize the COM library before they can call COM library functions
> CoInitialize_(0)

Is this really necessary? Seems to work fine without it? Good code, BTW. :)
Yes, it is necessary. If it works without it, it just means some Dll or other code already called it. (My guess is the RichEdit dll for the EditorGadget did it)
But you cannot rely on this as you do not know when the other code will be done and uninitialize COM.

srod:
It doesn't work on the IDE because Scintilla doesn't support Active Accessibility.

Re: Capturing Text from under your mouse cursor

Posted: Sun Aug 31, 2008 8:51 pm
by srod
freak wrote:srod:
It doesn't work on the IDE because Scintilla doesn't support Active Accessibility.
Understood. :)

Nice to see this in purebasic!

Posted: Tue Sep 02, 2008 2:44 pm
by thomas_nibu
Indeed good job by fizban converting this to purebasic from VC++.


http://nibuthomas.wordpress.com

Re: Capturing Text from under your mouse cursor

Posted: Fri Oct 03, 2008 10:02 am
by PB
Is there a way to know the window handle under the pointer, too?

Posted: Fri Oct 03, 2008 10:06 am
by Trond
WindowFromPoint()?

Posted: Fri Oct 03, 2008 10:28 am
by srod
Careful with WindowFromPoint_() as it's internal prototype has now changed between PB 4.3 beta 2 and beta 3. This means that between PB 4.2 and 4.3 (the latest beta) WindowFromPoint_() has gone from accepting two parameters of type long to one of type quad.

PB 4.3 beta 3 onwards :

Code: Select all

x = DesktopMouseX()
y = DesktopMouseY()
pos.q = y<<32 + x
hWnd = WindowFromPoint_(pos)
(Note there is a bug in PB 4.3 beta 3 x64 which means that this function does not currently work in 64-bit PB! :wink: )

Posted: Fri Oct 03, 2008 11:54 am
by PB
Thanks guys, but I meant from using the procedure above, because it can
get details from things that WindowFromPoint can't. So I was hoping there'd
be something like the "*pIAcc\get_accName(vt, @pName)" part but for getting
the handle, instead of the name.

Posted: Thu Oct 16, 2008 10:23 pm
by Michael Vogel
Great code, thanks!

I copied it to my runner program (a kind of a permanently active swiss knife tool) which just copies the text under the mouse cursor to the clipboard when pressing [win]-[c]...

The only point is, that the code is able to get the text from dialog elements or the content from text fields, but not from icon list tables, is that true?

Michael

Re: Capturing Text from under your mouse cursor

Posted: Fri Jan 21, 2011 5:19 pm
by fizban
I do not know when this stopped working, but I am using PB 4.51 and the hand cursor is not shown on the ImageGadget. Is there any problem with DrawImage (handcursor,0,0) related to a change in the 2D libraries used by PB?

Re: Capturing Text from under your mouse cursor

Posted: Fri Jan 21, 2011 5:37 pm
by fizban
It seems to be workin just replacing

Code: Select all

DrawImage (handcursor,0,0)
with

Code: Select all

DrawIconEx_(hdc, 0,0, handcursor, 0,0,0,0,#DI_NORMAL)
and

Code: Select all

DrawImage (nocursor,0,0)
with

Code: Select all

DrawIconEx_(hdc, 0,0, nocursor, 0,0,0,0,#DI_NORMAL)

Re: Capturing Text from under your mouse cursor

Posted: Tue Feb 17, 2015 4:56 pm
by Dude
The code in the first post is returning Asian characters for me instead of English text, which I'm guessing means it's not written to handle Unicode character sets. I've tried increasing the Space() amounts but that didn't help. Can someone please help me get it working? :mrgreen: I also tried different code page flags from the bottom of https://msdn.microsoft.com/en-us/librar ... s.71).aspx but that didn't help either.