马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
注册鼠标钩子
- // 注册鼠标钩子
- HHOOK hMouseHook;
- hMouseHook = SetWindowsHookEx(WH_MOUSE_LL,
- MouseProc,
- GetModuleHandle(NULL),
- 0);
- // 取消鼠标钩子
- UnhookWindowsHookEx(hMouseHook);
- hMouseHook = nullptr;
复制代码 上述代码中MouseProc方法用于处理系统的鼠标消息
处理鼠标消息
- LRESULT MouseHook::MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
- {
- static QPoint pos;
- static qint64 lastTriggerTime = 0;
- if (nCode >= 0) {
- if (wParam == WM_LBUTTONDOWN) {
- pos = QCursor::pos();
- }
- else if (wParam == WM_LBUTTONUP) {
- if (pos != QCursor::pos()) {
- timer->start(280); //拖拽
- }
- qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
- if (currentTime - lastTriggerTime <= 500) {
- timer->start(280); //双击
- }
- lastTriggerTime = currentTime;
- }
- }
- return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
- }
复制代码 这段代码中,我们使用一个QTimer来处理双击或拖拽选中文本的操作。
文本选中后的处理方法
- void MouseHook::processMouseUp()
- {
- auto textGetter = new TextGetter(this);
- connect(textGetter,
- &TextGetter::resultReady,
- this,
- &MouseHook::onTextReady,
- Qt::ConnectionType::QueuedConnection);
- textGetter->start();
- }
复制代码 TextGetter是一个继承自QThread的类,我们将在一个新线程中去获取用户选中的文本。
获取选中文本的第一种情况
- QString TextGetter::getSelectedTextByUIAutomation() {
- try {
- auto hr = CoInitialize(NULL);
- if (FAILED(hr))
- {
- CoUninitialize();
- return "";
- }
- CComPtr<IUIAutomation> automation;
- hr = CoCreateInstance(CLSID_CUIAutomation, nullptr, CLSCTX_INPROC_SERVER, IID_IUIAutomation,(void**)(&automation));
- if (FAILED(hr))
- {
- CoUninitialize();
- return "";
- }
- CComPtr<IUIAutomationElement> focusedElement;
- hr = automation->GetFocusedElement(&focusedElement);
- if (FAILED(hr) || !focusedElement)
- {
- CoUninitialize();
- return "";
- }
- CComPtr<IUIAutomationTextPattern> textPattern;
- hr = focusedElement->GetCurrentPatternAs(UIA_TextPatternId, IID_PPV_ARGS(&textPattern));
- if (FAILED(hr) || !textPattern)
- {
- CoUninitialize();
- return "";
- }
- CComPtr<IUIAutomationTextRangeArray> selection;
- hr = textPattern->GetSelection(&selection);
- if (FAILED(hr) || !selection)
- {
- CoUninitialize();
- return "";
- }
- CComPtr<IUIAutomationTextRange> range;
- hr = selection->GetElement(0, &range);
- if (FAILED(hr) || !range)
- {
- CoUninitialize();
- return "";
- }
- CComBSTR text;
- range->GetText(-1, &text);
- std::wstring ws(text, SysStringLen(text));
- CoUninitialize();
- return QString::fromStdWString(ws);
- }
- catch (std::exception& e) {
- return "";
- }
- }
复制代码 这段代码使用 Microsoft UI Automation (UIA) API 从当前具有焦点的 UI 元素中获取选中文本的方法。但有的时候这种方法获取不到想要的文本(老式窗口中的文本)
获取选中文本的第二种情况
当第一种情况获取到的文本是空时,就要尝试第二种情况
- auto hwnd = getCurrentHwnd();
- if (!hwnd) {
- return "";
- }
- auto cache = cacheClipboard();
- sendCtrlC();
- str = getClipboardText();
- if (str.isEmpty()) {
- CloseClipboard();
- return "";
- }
- restoreClipboard(cache);
- CloseClipboard();
复制代码 这种情况,先获取系统当前聚焦的窗口,然后缓存当前剪切板,然后发送Ctrl+C复制此窗口选中的文本,然后获取剪切板内的文本,然后把之前缓存的内容存入剪切板。
下面我们看看这些实当代码:
获取系统当前聚焦的窗口
- HWND TextGetter::getCurrentHwnd()
- {
- HWND hwnd = GetForegroundWindow();
- DWORD threadId = GetWindowThreadProcessId(hwnd, NULL);
- AttachThreadInput(GetCurrentThreadId(), threadId, TRUE);
- hwnd = GetFocus();
- AttachThreadInput(GetCurrentThreadId(), threadId, FALSE);
- POINT pt;
- GetCursorPos(&pt);
- RECT rect;
- GetWindowRect(hwnd, &rect);
- if (pt.x<rect.left || pt.y<rect.top || pt.x>rect.right || pt.y>rect.bottom) {
- return nullptr;
- }
- return hwnd;
- }
复制代码 假如聚焦的窗口与鼠标所在位置的窗口不是一个窗口,那么我们取消任务。
缓存剪切板的内容
- ClipboardData TextGetter::cacheClipboard()
- {
- OpenClipboard(nullptr);
- ClipboardData cache;
- UINT format = 0;
- while ((format = EnumClipboardFormats(format)) != 0) {
- HANDLE hData = GetClipboardData(format);
- if (hData) {
- SIZE_T size = GlobalSize(hData);
- HGLOBAL hCopy = GlobalAlloc(GMEM_MOVEABLE, size);
- if (hCopy) {
- void* pDest = GlobalLock(hCopy);
- void* pSource = GlobalLock(hData);
- if (pDest && pSource) {
- memcpy(pDest, pSource, size);
- }
- GlobalUnlock(hData);
- GlobalUnlock(hCopy);
- cache.push_back({ format, hCopy });
- }
- }
- }
- EmptyClipboard();
- CloseClipboard();
- return cache;
- }
复制代码 发送Ctrl+C按键消息
- void TextGetter::sendCtrlC()
- {
- INPUT inputs[4] = { 0 };
- inputs[0].type = INPUT_KEYBOARD;
- inputs[0].ki.wVk = VK_CONTROL;
- inputs[1].type = INPUT_KEYBOARD;
- inputs[1].ki.wVk = 'C';
- inputs[2].type = INPUT_KEYBOARD;
- inputs[2].ki.wVk = 'C';
- inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;
- inputs[3].type = INPUT_KEYBOARD;
- inputs[3].ki.wVk = VK_CONTROL;
- inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;
- SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
- QThread::msleep(360);
- }
复制代码 按键发送乐成后须要等待360毫秒
获取剪切板的内容
- QString TextGetter::getClipboardText()
- {
- OpenClipboard(nullptr);
- if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) {
- CloseClipboard();
- return "";
- }
- HANDLE hData = GetClipboardData(CF_UNICODETEXT);
- if (hData == nullptr) {
- CloseClipboard();
- return "";
- }
- LPCWSTR pText = static_cast<LPCWSTR>(GlobalLock(hData));
- if (pText == nullptr) {
- CloseClipboard();
- return "";
- }
- QString result = QString::fromWCharArray(pText);
- GlobalUnlock(hData);
- CloseClipboard();
- return result;
- }
复制代码 不要猜疑发送按键Ctrl+C这个方案是否可行,有道词典就是这么干的。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |