How to retrieve the selected text from the active window
Asked Answered
C

4

15

I am trying to create a simple open source utility for windows using Python that can perform user-defined actions on the selected text of the currently active window. The utility should be activated using a pre-defined keyboard shortcut.

Usage is partially outlined in the following example:

  1. The user selects some text using the mouse or the keyboard (in any application window)
  2. The user presses a pre-defined keyboard shortcut
  3. The selected text is retrieved by our utility or copied to clipboard (both approaches should be fine)
  4. The keyboard shortcut-dependent action is performed on the selected text

What puzzles me is step 3. How the selected text is retrieved from the active window. This should work with all applications.

I use the pywin32 module.

Thanks in advance for your answers and tips.

Update #1:

Turns out that there are two approaches to accomplish the task:

  1. Find the active window, then send a message/keystroke (Ctrl-C) to it in order to copy the selected text to the clipboard. Then the utility can work on the text by accessing it using the clipboard-related functions.
  2. Find the active Window, then retrieve the selected text directly (without copying it to clipboard). This seems more difficult than the 1st approach.

As starting points:

Get the active window ID as Anurag Uniyal has pointed out in his reply.

Or get the window object with the following code:

import win32ui
wnd = win32ui.GetForegroundWindow()
print wnd.GetWindowText()
Corinthians answered 17/6, 2009 at 13:54 Comment(4)
Can you clarify whether or not this utility is actually creating the active window or is this active window from a different application?Tontine
The "active window" is a window from a different application. This utility should run in the background (or systray) and should be activated with a pre-defined keystroke.Corinthians
Have you figure out how to retrieve the selected text ?Epicanthus
Have you figure out how to retrieve the selected text ???Sudatory
C
2

the code below will work only on simple text boxes (just did it in VB6, and ported to python)

edit: it was tested only on python 2.6

from ctypes import *
import win32gui
import win32api
import win32con


user32 = windll.user32
kernel32 = windll.kernel32

class RECT(Structure):
 _fields_ = [
     ("left", c_ulong),
     ("top", c_ulong),
     ("right", c_ulong),
     ("bottom", c_ulong)
 ]

class GUITHREADINFO(Structure):
 _fields_ = [
     ("cbSize", c_ulong),
     ("flags", c_ulong),
     ("hwndActive", c_ulong),
     ("hwndFocus", c_ulong),
     ("hwndCapture", c_ulong),
     ("hwndMenuOwner", c_ulong),
     ("hwndMoveSize", c_ulong),
     ("hwndCaret", c_ulong),
     ("rcCaret", RECT)
 ]



def get_selected_text_from_front_window(): # As String
    ''' vb6 to python translation '''

    gui = GUITHREADINFO(cbSize=sizeof(GUITHREADINFO))
    txt=''
    ast_Clipboard_Obj=None
    Last_Clipboard_Temp = -1


    user32.GetGUIThreadInfo(0, byref(gui))

    txt = GetCaretWindowText(gui.hwndCaret, True)

    '''
    if Txt = "" Then
        LastClipboardClip = ""
        Last_Clipboard_Obj = GetClipboard
        Last_Clipboard_Temp = LastClipboardFormat
        SendKeys "^(c)"
        GetClipboard
        Txt = LastClipboardClip
        if LastClipboardClip <> "" Then Txt = LastClipboardClip
        RestoreClipboard Last_Clipboard_Obj, Last_Clipboard_Temp
        print "clbrd: " + Txt
    End If
    '''    
    return txt



def GetCaretWindowText(hWndCaret, Selected = False): # As String

    startpos =0
    endpos =0

    txt = ""

    if hWndCaret:

        buf_size = 1 + win32gui.SendMessage(hWndCaret, win32con.WM_GETTEXTLENGTH, 0, 0)
        if buf_size:
            buffer = win32gui.PyMakeBuffer(buf_size)
            win32gui.SendMessage(hWndCaret, win32con.WM_GETTEXT, buf_size, buffer)
            txt = buffer[:buf_size]

        if Selected and buf_size:
            selinfo  = win32gui.SendMessage(hWndCaret, win32con.EM_GETSEL, 0, 0)
            endpos   = win32api.HIWORD(selinfo)
            startpos = win32api.LOWORD(selinfo)
            return txt[startpos: endpos]

    return txt

if __name__ == '__main__':
    print get_selected_text_from_front_window()
Caesarea answered 23/9, 2011 at 23:40 Comment(2)
I tested your code with Python 3 , it only returns <memory at 0x014775E0>, no text .Epicanthus
Me too, I tested your code with 3.7.3 python, return an empty stringSatanic
L
1

It won't be trivial but here is the starting point

import win32gui
hwnd = win32gui.GetForegroundWindow()
print win32gui.GetWindowText(hwnd)

Maybe you will have to use FindWindow,FindWindowEx to get child windows with focus

edit: also while experimenting use spy++ to see how it retrieves information about various windows, see hwnd, window class etc

basically if you can find a example in C/C++/C# it won't be difficult to translate that into pywin32 equivalent, so in a way it is win32 api specific question

Langham answered 17/6, 2009 at 14:52 Comment(2)
I've been getting the active window object with the following: import win32ui wnd = win32ui.GetForegroundWindow() print wnd.GetWindowText() But I have difficulties in getting to the selected text from there. Thanks for the tips. I will look into spy++.Corinthians
Hello,I have question about basically if you can find a example in C/C++/C# it won't be difficult to translate that into pywin32 equivalent, so in a way it is win32 api specific question Can i use same for 64 bit machines?Sudatory
T
1

You're far better off using the Ctrl-C method. Fetching text directly will work for something like an edit control, but is useless for retrieving text that an application has painted directly on its own window.

Tiossem answered 17/6, 2009 at 20:58 Comment(2)
Thanks. This assumes that all applications, which support text selection, make use of the clipboard. This is probably true for 99.99% of the applications, but do you happen to know if this is the rule?Corinthians
Keep in mind there are a few applications that do support clipboard copy of text, but assign a different meaning to Ctrl+C than "clipboard copy." One example that comes to mind is the command shell (cmd.exe).Snatch
B
0

It appears that while the clipboard and associated copy and paste shortcuts are ubiquitous, they must be added to applications by developers. The best bet is to use a listener to capture when ctrl+c is activated, check that the clipboard is not in use and has data on it, and then manipulate the data from there.
You can check out Microsoft's dev page here:

https://learn.microsoft.com/en-us/windows/win32/dataxchg/using-the-clipboard#implementing-the-cut-copy-and-paste-commands

Blen answered 5/6, 2020 at 1:14 Comment(2)
Can you provide an example code using pywin32? Windows api is not easy enough for most python developers.Zygophyllaceous
I would suggest looking over example #2 programcreek.com/python/example/104590/win32api.keybd_event I am currently working with pynput for listening pypi.org/project/pynputBlen

© 2022 - 2024 — McMap. All rights reserved.