Capturing Text from under your mouse cursor

Share your advanced PureBasic knowledge/code with the community.
fizban
User
User
Posts: 31
Joined: Thu Sep 20, 2007 7:36 am
Location: Spain

Capturing Text from under your mouse cursor

Post 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) 
Derek
Addict
Addict
Posts: 2356
Joined: Wed Apr 07, 2004 12:51 am
Location: England

Post by Derek »

That works really well, thanks for sharing.
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post by srod »

Very impressive. 8)

Doesn't work though for text in the IDE main window; the scintilla control.
I may look like a mule, but I'm not a complete ass.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Capturing Text from under your mouse cursor

Post 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. :)
freak
PureBasic Team
PureBasic Team
Posts: 5929
Joined: Fri Apr 25, 2003 5:21 pm
Location: Germany

Re: Capturing Text from under your mouse cursor

Post 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.
quidquid Latine dictum sit altum videtur
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Re: Capturing Text from under your mouse cursor

Post by srod »

freak wrote:srod:
It doesn't work on the IDE because Scintilla doesn't support Active Accessibility.
Understood. :)
I may look like a mule, but I'm not a complete ass.
thomas_nibu
New User
New User
Posts: 1
Joined: Tue Sep 02, 2008 2:41 pm
Location: India

Nice to see this in purebasic!

Post by thomas_nibu »

Indeed good job by fizban converting this to purebasic from VC++.


http://nibuthomas.wordpress.com
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Capturing Text from under your mouse cursor

Post by PB »

Is there a way to know the window handle under the pointer, too?
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

WindowFromPoint()?
srod
PureBasic Expert
PureBasic Expert
Posts: 10589
Joined: Wed Oct 29, 2003 4:35 pm
Location: Beyond the pale...

Post 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: )
I may look like a mule, but I'm not a complete ass.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Post 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.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
Michael Vogel
Addict
Addict
Posts: 2680
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post 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
fizban
User
User
Posts: 31
Joined: Thu Sep 20, 2007 7:36 am
Location: Spain

Re: Capturing Text from under your mouse cursor

Post 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?
fizban
User
User
Posts: 31
Joined: Thu Sep 20, 2007 7:36 am
Location: Spain

Re: Capturing Text from under your mouse cursor

Post 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)
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Capturing Text from under your mouse cursor

Post 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.
Post Reply