使用 C++\Qt 从当前窗口中获取选定的文本

Posted

技术标签:

【中文标题】使用 C++\\Qt 从当前窗口中获取选定的文本【英文标题】:Get selected text from current window with C++ \ Qt使用 C++\Qt 从当前窗口中获取选定的文本 【发布时间】:2018-03-28 22:49:50 【问题描述】:

我正在尝试从我的 Qt 应用程序中另一个应用程序的活动窗口中获取选定的文本。 在 Linux 上,我只在 Selection 模式下使用 QClipboard。 在 Windows 上,我正在尝试将 Ctrl + C 发送到系统:

INPUT copyText;
copyText.type = INPUT_KEYBOARD;
copyText.ki.wScan = 0;
copyText.ki.time = 0;
copyText.ki.dwExtraInfo = 0;

Sleep(200);
// Press the "Ctrl" key
copyText.ki.wVk = VK_CONTROL;
copyText.ki.dwFlags = 0; // 0 for key press
SendInput(1, &copyText, sizeof(INPUT));

// Press the "C" key
copyText.ki.wVk = 'C';
copyText.ki.dwFlags = 0; // 0 for key press
SendInput(1, &copyText, sizeof(INPUT));

Sleep(50);

// Release the "C" key
copyText.ki.wVk = 'C';
copyText.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &copyText, sizeof(INPUT));

// Release the "Ctrl" key
copyText.ki.wVk = VK_CONTROL;
copyText.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &copyText, sizeof(INPUT));
Sleep(50);

但是这个 hack 不能正常工作 - 有时我没有得到选择。我认为这可能是由使用此代码调用函数的热键引起的,并且在此代码运行时某些键仍被按下。如何检查 QKeySequenceEdit 中是否没有按下每个键?或者如何检查是否没有按下任何键? 或者有没有更简单的方法从 Windows 上的活动窗口中获取选定的文本?

【问题讨论】:

为什么不继续使用 QClipBoard for windows? nInputs=1 调用SendInput() 是(几乎总是)一个错误。这违背了使用SendInput() 而不是keybd_event() 的目的。创建一个包含多个INPUTs 的数组,并将整个数组一次性传递给SendInput(),并将nInputs 设置为数组中INPUTs 的数量。并摆脱Sleep() 电话,它们不是必需的。如果您需要检查给定的密钥是否已经关闭,请使用GetAsyncKeyState()。或者,尝试使用GetGUIThreadInfo() 获取当前具有输入焦点的HWND,然后向其发送WM_COPY 消息。 或者,如果HWND 是标准的编辑控件,您可以使用EM_GETSELWM_GETTEXT 的组合来提取选定的文本,而无需通过剪贴板。或者,如果HWND 是标准RichEdit 控件,则使用EM_EXGETSELEM_GETSELTEXT 的组合。或者,改用UI Automation。 @eyllanesc,因为 QClipboard 在选择模式下的 Windows 上不起作用。 @RemyLebeau,感谢您的解释!哪种解决方案更通用,可以从任何应用程序中获取选择,发送Ctrl + C 或发送WM_COPY 消息? @ГенаЧерныщук 那么,为什么要使用 Qt 标签呢? 【参考方案1】:

我获取选定文本的解决方案:

QString MainWindow::selectedText()

    QString selectedText;
#if defined(Q_OS_LINUX)
    selectedText = QApplication::clipboard()->text(QClipboard::Selection);
#elif defined(Q_OS_WIN) // Send Ctrl + C to get selected text
    // Save original clipboard data
    QVariant originalClipboard;
    if (QApplication::clipboard()->mimeData()->hasImage())
        originalClipboard = QApplication::clipboard()->image();
    else
        originalClipboard = QApplication::clipboard()->text();

    // Wait until the hot key is pressed
    while (GetAsyncKeyState(translateSelectedHotkey->currentNativeShortcut().key) || GetAsyncKeyState(VK_CONTROL)
           || GetAsyncKeyState(VK_MENU) || GetAsyncKeyState(VK_SHIFT))
        Sleep(50);

    // Generate key sequence
    INPUT copyText[4];

    // Set the press of the "Ctrl" key
    copyText[0].ki.wVk = VK_CONTROL;
    copyText[0].ki.dwFlags = 0; // 0 for key press
    copyText[0].type = INPUT_KEYBOARD;

    // Set the press of the "C" key
    copyText[1].ki.wVk = 'C';
    copyText[1].ki.dwFlags = 0;
    copyText[1].type = INPUT_KEYBOARD;

    // Set the release of the "C" key
    copyText[2].ki.wVk = 'C';
    copyText[2].ki.dwFlags = KEYEVENTF_KEYUP;
    copyText[2].type = INPUT_KEYBOARD;

    // Set the release of the "Ctrl" key
    copyText[3].ki.wVk = VK_CONTROL;
    copyText[3].ki.dwFlags = KEYEVENTF_KEYUP;
    copyText[3].type = INPUT_KEYBOARD;

    // Send key sequence to system
    SendInput(4, copyText, sizeof(INPUT));

    // Wait for the clipboard to change
    QEventLoop loop;
    QTimer timer; // Add a timer for the case where the text is not selected
    loop.connect(QApplication::clipboard(), &QClipboard::changed, &loop, &QEventLoop::quit);
    loop.connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
    timer.start(1000);
    loop.exec();

    // Translate the text from the clipboard if the selected text was not copied
    if (timer.isActive())
        return QApplication::clipboard()->text();
    else
        timer.stop();

    // Get clipboard data
    selectedText = QApplication::clipboard()->text();

    // Return original clipboard
    if (originalClipboard.type() == QVariant::Image)
        QApplication::clipboard()->setImage(originalClipboard.value<QImage>());
    else
        QApplication::clipboard()->setText(originalClipboard.toString());
#endif
    return selectedText;

为了设置全局快捷方式,我使用了QHotkey。从 QHotkey 我使用 currentNativeShortcut().key 方法获得本机键码。

【讨论】:

以上是关于使用 C++\Qt 从当前窗口中获取选定的文本的主要内容,如果未能解决你的问题,请参考以下文章

是否可以获得任何窗口的选定文本,包括非 UI 自动化元素?

使用 javascript 从指向不同域的 iframe 中获取选定的文本

Qt Quick:如何从 ComboBox 获取当前文本

Qt Quick:如何从ComboBox获取当前文本

MFC 获取Combo Box控件 当前选定项的序号和文本内容

Qt - 如何从 QListWidget 中获取选定的自定义项目?