Как получить выделенный текст из активного окна

Я пытаюсь создать простую утилиту с открытым исходным кодом для Windows, используя Python, которая может выполнять определенные пользователем действия с выделенным текстом текущего активного окна. Утилиту следует активировать с помощью заранее заданного сочетания клавиш.

Использование частично описано в следующем примере:

  1. Пользователь выделяет текст с помощью мыши или клавиатуры (в любом окне приложения)
  2. Пользователь нажимает заранее заданное сочетание клавиш.
  3. Выбранный текст извлекается нашей утилитой или копируется в буфер обмена (оба подхода подойдут)
  4. Действие, зависящее от сочетания клавиш, выполняется над выделенным текстом.

Меня озадачивает шаг 3. Как выбранный текст извлекается из активного окна. Это должно работать со всеми приложениями.

Я использую модуль pywin32.

Заранее благодарим за ответы и советы.

Обновление №1:

Оказывается, есть два подхода к решению задачи:

  1. Найдите активное окно, затем отправьте ему сообщение / нажмите клавишу (Ctrl-C), чтобы скопировать выделенный текст в буфер обмена. Затем утилита может работать с текстом, обращаясь к нему с помощью функций, связанных с буфером обмена.
  2. Найдите активное окно, затем извлеките выделенный текст напрямую (не копируя его в буфер обмена). Это кажется более сложным, чем первый подход.

В качестве отправных точек:

Получите идентификатор активного окна, как указал Анураг Униял в своем ответить.

Или получите объект окна с помощью следующего кода:

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

person George Notaras    schedule 17.06.2009    source источник
comment
Можете ли вы уточнить, действительно ли эта утилита создает активное окно или это активное окно из другого приложения?   -  person Jay Atkinson    schedule 17.06.2009
comment
Активное окно - это окно из другого приложения. Эта утилита должна работать в фоновом режиме (или в системном трее) и должна быть активирована заранее заданным нажатием клавиши.   -  person George Notaras    schedule 17.06.2009
comment
Вы придумали, как получить выделенный текст?   -  person iMath    schedule 06.11.2015
comment
Вы придумали, как получить выделенный текст ???   -  person Mahmoud Hossam    schedule 03.05.2020


Ответы (4)


приведенный ниже код будет работать только с простыми текстовыми полями (только что сделал это в 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()
person Berry Tsakala    schedule 23.09.2011
comment
Я тестировал ваш код на Python 3, он возвращает только ‹память на 0x014775E0›, без текста. - person iMath; 06.11.2015
comment
Я тоже, я тестировал ваш код с помощью Python 3.7.3, вернул пустую строку - person Hzzkygcs; 05.12.2019

Вам гораздо лучше использовать метод Ctrl-C. Получение текста напрямую будет работать для чего-то вроде элемента управления редактированием, но бесполезно для извлечения текста, нарисованного приложением непосредственно в собственном окне.

person Bob Moore    schedule 17.06.2009
comment
Спасибо. Это предполагает, что все приложения, поддерживающие выделение текста, используют буфер обмена. Вероятно, это верно для 99,99% приложений, но знаете ли вы, является ли это правилом? - person George Notaras; 18.06.2009
comment
Имейте в виду, что есть несколько приложений, которые поддерживают копирование текста из буфера обмена, но присваивают Ctrl + C другое значение, чем копирование из буфера обмена. Один из примеров, который приходит на ум, - это командная оболочка (cmd.exe). - person Jon Schneider; 18.06.2009

Это будет нетривиально, но вот отправная точка

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

Возможно, вам придется использовать _2 _, _ 3_, чтобы получить дочерние окна с фокусом

edit: также во время экспериментов используйте spy ++, чтобы увидеть, как он извлекает информацию о различных окнах, см. hwnd, класс окна и т. д.

в основном, если вы можете найти пример на C / C ++ / C #, не составит труда перевести это в эквивалент pywin32, так что в каком-то смысле это конкретный вопрос win32 api

person Anurag Uniyal    schedule 17.06.2009
comment
Я получаю активный объект окна со следующим: import win32ui wnd = win32ui.GetForegroundWindow () print wnd.GetWindowText () Но мне трудно добраться до выделенного текста оттуда. Спасибо за советы. Я посмотрю в spy ++. - person George Notaras; 17.06.2009
comment
Здравствуйте, у меня есть вопрос о 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 Могу ли я использовать то же самое для 64-битных машин? - person Mahmoud Hossam; 03.05.2020

Похоже, что хотя буфер обмена и связанные с ним ярлыки для копирования и вставки широко распространены, они должны добавляться в приложения разработчиками. Лучше всего использовать прослушиватель для захвата, когда активирован ctrl + c, проверить, что буфер обмена не используется и в нем есть данные, а затем управлять данными оттуда. Вы можете проверить страницу разработчиков Microsoft здесь.

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

person elarnia    schedule 05.06.2020
comment
Можете ли вы предоставить пример кода с использованием pywin32? Windows api не является достаточно простой задачей для большинства разработчиков Python. - person PaleNeutron; 05.06.2020
comment
Я бы посоветовал просмотреть пример № 2 programcreek.com/python/example/104590/ win32api.keybd_event В настоящее время я работаю с pynput для прослушивания pypi.org/project/pynput - person elarnia; 11.06.2020