Как я получаю выделенный текст от сфокусированного окна с помощью собственного Win32 API?

Мое приложение. будет работать на системной попытке контролировать для горячей клавиши; когда пользователь выбирает некоторый текст в каком-либо окне и нажимает горячую клавишу, как я получаю выделенный текст, когда я получаю сообщение WM_HOTKEY?

Для получения текста на буфере обмена я пытался отправить Ctrl + C использование keybd_event() и SendInput() к активному окну (GetActiveWindow()) и окно forground (GetForegroundWindow()); испытанные комбинации среди них;все напрасно. я могу получить выбранный текст сфокусированного окна в Windows с плоскостью системные API Win32?

18
задан legends2k 12 February 2010 в 13:10
поделиться

3 ответа

TL; DR: Да, есть способ сделать это, используя простые системные API Win32, но его трудно реализовать правильно.

WM_COPY и WM_GETTEXT могут работать, но не во всех случаях. Они зависят от того, правильно ли обрабатывает запрос принимающее окно, а во многих случаях это не так. Позвольте мне рассмотреть один из возможных способов сделать это. Возможно, это не так просто, как вы надеялись, но что есть в наполненном приключениями мире программирования под Win32? Готовый? Ok. Пойдем.

Сначала нам нужно получить HWND id целевого окна. Есть много способов сделать это. Один из таких подходов - тот, который вы упомянули выше: получите окно переднего плана, а затем окно с фокусом и т. Д. Однако есть одна огромная ошибка, о которой многие люди забывают. После того, как вы получите окно переднего плана, вы должны AttachThreadInput получить окно с фокусом. В противном случае GetFocus () просто вернет NULL .

Есть гораздо более простой способ. Просто (пропустите) используйте функции GUITREADINFO. Это намного безопаснее, поскольку позволяет избежать всех скрытых опасностей, связанных с подключением вашего входного потока к другой программе.

LPGUITHREADINFO lpgui = NULL;
HWND target_window = NULL;

if( GetGUIThreadInfo( NULL, lpgui ) )
    target_window = lpgui->hwndFocus;
else
{
    // You can get more information on why the function failed by calling
    // the win32 function, GetLastError().
}

Отправка нажатий клавиш для копирования текста немного сложнее ...

Мы собираемся использовать SendInput вместо keybd_event, потому что это быстрее и, что наиболее важно, не может быть испорчено одновременным вводом пользователем, или другие программы, имитирующие нажатия клавиш.

Это означает, что программа должна будет работать в Windows XP или более поздней версии, так что извините, если вы используете 98!

// We're sending two keys CONTROL and 'V'. Since keydown and keyup are two
// seperate messages, we multiply that number by two.
int key_count = 4;

INPUT* input = new INPUT[key_count];
for( int i = 0; i < key_count; i++ )
{
    input[i].dwFlags = 0;
    input[i].type = INPUT_KEYBOARD;
}

input[0].wVK = VK_CONTROL;
input[0].wScan = MapVirtualKey( VK_CONTROL, MAPVK_VK_TO_VSC );
input[1].wVK = 0x56 // Virtual key code for 'v'
input[1].wScan = MapVirtualKey( 0x56, MAPVK_VK_TO_VSC );
input[2].dwFlags = KEYEVENTF_KEYUP;
input[2].wVK = input[0].wVK;
input[2].wScan = input[0].wScan;
input[3].dwFlags = KEYEVENTF_KEYUP;
input[3].wVK = input[1].wVK;
input[3].wScan = input[1].wScan;

if( !SendInput( key_count, (LPINPUT)input, sizeof(INPUT) ) )
{
    // You can get more information on why this function failed by calling
    // the win32 function, GetLastError().
}

Вот. Это было не так уж и плохо, не так ли?

Теперь нам просто нужно взглянуть на то, что находится в буфере обмена. Это не так просто, как вы думаете. «Буфер обмена» может содержать несколько представлений одного и того же объекта. Приложение, которое активно при копировании в буфер обмена, контролирует, что именно помещать в буфер обмена.

Когда вы копируете текст из Microsoft Office, например, он помещает данные RTF в буфер обмена вместе с простым текстовым представлением того же текста. Таким образом, вы можете вставить его в блокнот и текстовый блокнот. Wordpad будет использовать формат RTF, а блокнот - обычный текстовый формат.

Для этого простого примера предположим, что нас интересует только открытый текст.

if( OpenClipboard(NULL) )
{
    // Optionally you may want to change CF_TEXT below to CF_UNICODE.
    // Play around with it, and check out all the standard formats at:
    // http://msdn.microsoft.com/en-us/library/ms649013(VS.85).aspx
    HGLOBAL hglb = GetClipboardData( CF_TEXT );
    LPSTR lpstr = GlobalLock(hglb);

    // Copy lpstr, then do whatever you want with the copy.

    GlobalUnlock(hglb);
    CloseClipboard();
}
else
{
    // You know the drill by now. Check GetLastError() to find out what
    // went wrong. :)
}

И вот оно! Просто убедитесь, что вы скопировали lpstr в какую-то переменную, которую хотите использовать, не используйте lpstr напрямую, так как мы должны передать контроль над содержимым буфера обмена, прежде чем закрывать его.

Поначалу программирование на Win32 может быть довольно сложным, но через некоторое время ... оно все еще пугает.

Ура!

20
ответ дан 30 November 2019 в 08:43
поделиться

Попробуйте отправить сообщение (WM_COPY и т. Д.).

0
ответ дан 30 November 2019 в 08:43
поделиться

Попробуйте добавить Sleep () после каждого SendInput (). Некоторые приложения просто не так быстро улавливают ввод с клавиатуры.

3
ответ дан 30 November 2019 в 08:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: