如何从活动窗口获取选定文本

15 投票
4 回答
17859 浏览
提问于 2025-04-15 12:18

我正在尝试用Python创建一个简单的开源工具,专门用于Windows系统,能够对当前活动窗口中选中的文本执行用户自定义的操作。这个工具应该可以通过预设的快捷键来激活。

使用方法大致如下:

  1. 用户可以用鼠标或键盘在任何应用窗口中选择一些文本。
  2. 用户按下预设的快捷键。
  3. 我们的工具会获取选中的文本,或者将其复制到剪贴板(这两种方式都可以)。
  4. 根据快捷键执行与选中文本相关的操作。

我比较困惑的是第3步如何从活动窗口中获取选中的文本。这个功能应该适用于所有应用。

我使用的是pywin32模块。

谢谢大家的回答和建议。

更新 #1

结果发现有两种方法可以完成这个任务:

  1. 找到活动窗口,然后发送一个消息/按键(Ctrl-C)给它,以便将选中的文本复制到剪贴板。然后,工具可以通过剪贴板相关的功能来处理这些文本。
  2. 找到活动窗口,然后直接获取选中的文本(不需要复制到剪贴板)。这似乎比第一种方法更复杂。

作为起点:

可以获取活动窗口的ID,正如Anurag Uniyal在他的回复中提到的那样。

或者用以下代码获取窗口对象:

import win32ui
wnd = win32ui.GetForegroundWindow()
print wnd.GetWindowText()

4 个回答

1

这可能不是件简单的事,但这是一个起点。

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

你可能需要用到 FindWindowFindWindowEx 来获取有焦点的子窗口。

补充:在实验的时候,可以使用 spy++ 来查看它是如何获取各种窗口的信息的,比如 hwnd、窗口类等等。

基本上,如果你能找到 C/C++/C# 的例子,把它转换成 pywin32 的对应代码并不难,所以从某种意义上说,这个问题是关于 win32 API 的。

1

你用Ctrl-C的方法会更好。直接获取文本在像编辑框这样的地方是有效的,但对于那些应用程序直接在自己窗口上显示的文本,这种方法就没用了。

2

下面的代码只适用于简单的文本框(我刚在VB6中写了这个,然后移植到Python中)。

补充说明:这个代码只在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()

撰写回答