#include "windowfinder.h" #include "QtImprovements/qsettingsplus.h" #include #include #include #ifdef Q_OS_WIN #include #include #include #endif WindowFinder::WindowFinder() {} WindowData WindowFinder::getFrontmostWindowProcess() { #ifdef Q_OS_WIN return WindowFinder::getWin32FrontmostWindowProcess(); #else return WindowData(); #endif } void WindowFinder::sendInputToFrontmostWindow(const QKeySequence &keys, const KeyEventType &type) { #ifdef Q_OS_WIN WindowFinder::sendWin32InputToFrontmostWindow(keys, type); #else return; #endif } void WindowData::importDataFromSetting(const QString &value) { QStringList values = value.split(QSettingsPlus::keyDataSeparator()); this->processName = values[0]; this->processPath = values[1]; values.removeAt(1); values.removeAt(0); this->processWindowTitle = values.join(QSettingsPlus::keyDataSeparator()); } #ifdef Q_OS_WIN WindowData WindowFinder::getWin32FrontmostWindowProcess() { WindowData data; HWND focusWindow = GetForegroundWindow(); DWORD processId; GetWindowThreadProcessId(focusWindow, &processId); HANDLE processHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, processId); TCHAR processPath[MAX_PATH]; DWORD pathLength = GetModuleFileNameExW(processHandle, NULL, processPath, MAX_PATH); assert(pathLength != ERROR_INSUFFICIENT_BUFFER); data.processPath = QString::fromWCharArray(processPath, pathLength); data.processName = QFileInfo(data.processPath).fileName(); /* Extract icon */ // HICON processIcon; // ExtractIconExW(processPath, 0, &processIcon, nullptr, 1); // QByteArray pixelBuffer; // WindowFinder::getWin32IconData(processIcon, 32, pixelBuffer); /* End extract icon */ WCHAR processTitle[512]; DWORD titleLength = GetWindowTextW(focusWindow, &processTitle[0], 512); assert(titleLength != ERROR_INSUFFICIENT_BUFFER); data.processWindowTitle = QString::fromWCharArray(processTitle, titleLength); CloseHandle(processHandle); return data; } // bool WindowFinder::getWin32IconData(HICON hIcon, int nColorBits, QByteArray &buffer) // { // HDC dc = CreateCompatibleDC(NULL); // const char iconHeader[6] = {0, 0, 1, 0, 1, 0}; // buffer.append(iconHeader); // ICONINFO iconInfo; // GetIconInfo(hIcon, &iconInfo); // BITMAPINFO bmInfo = {{0}}; // bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // bmInfo.bmiHeader.biBitCount = 0; // if (!GetDIBits(dc, iconInfo.hbmColor, 0, 0, NULL, &bmInfo, DIB_RGB_COLORS)) // return false; // int nBmInfoSize = sizeof(BITMAPINFOHEADER); // if (nColorBits < 24) // nBmInfoSize += sizeof(RGBQUAD) * (int) (static_cast(1) << nColorBits); // QVector bitmapInfo; // bitmapInfo.resize(nBmInfoSize); // BITMAPINFO *pBmInfo = (BITMAPINFO *) bitmapInfo.data(); // memcpy(pBmInfo, &bmInfo, sizeof(BITMAPINFOHEADER)); // if (!bmInfo.bmiHeader.biSizeImage) // return false; // QVector bits; // bits.resize(bmInfo.bmiHeader.biSizeImage); // pBmInfo->bmiHeader.biBitCount = nColorBits; // pBmInfo->bmiHeader.biCompression = BI_RGB; // if (!GetDIBits(dc, // iconInfo.hbmColor, // 0, // bmInfo.bmiHeader.biHeight, // bits.data(), // pBmInfo, // DIB_RGB_COLORS)) // return false; // BITMAPINFO maskInfo = {{0}}; // maskInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // maskInfo.bmiHeader.biBitCount = 0; // if (!GetDIBits(dc, iconInfo.hbmMask, 0, 0, NULL, &maskInfo, DIB_RGB_COLORS) // || maskInfo.bmiHeader.biBitCount != 1) // return false; // QVector maskBits; // maskBits.resize(maskInfo.bmiHeader.biSizeImage); // QVector maskInfoBytes; // maskInfoBytes.resize(sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD)); // BITMAPINFO *pMaskInfo = (BITMAPINFO *) maskInfoBytes.data(); // memcpy(pMaskInfo, &maskInfo, sizeof(maskInfo)); // if (!GetDIBits(dc, // iconInfo.hbmMask, // 0, // maskInfo.bmiHeader.biHeight, // maskBits.data(), // pMaskInfo, // DIB_RGB_COLORS)) { // return false; // } // IconDirEntry dir; // dir.nWidth = (quint8) pBmInfo->bmiHeader.biWidth; // dir.nHeight = (quint8) pBmInfo->bmiHeader.biHeight; // dir.nNumColorsInPalette = (nColorBits == 4 ? 16 : 0); // dir.nReserved = 0; // dir.nNumColorPlanes = 0; // dir.nBitsPerPixel = pBmInfo->bmiHeader.biBitCount; // dir.nDataLength = pBmInfo->bmiHeader.biSizeImage + pMaskInfo->bmiHeader.biSizeImage // + nBmInfoSize; // dir.nOffset = sizeof(dir) + sizeof(iconHeader); // const char *dirBuffer = reinterpret_cast(&dir); // buffer.append(dirBuffer); // pBmInfo->bmiHeader.biHeight *= 2; // pBmInfo->bmiHeader.biCompression = 0; // pBmInfo->bmiHeader.biSizeImage += pMaskInfo->bmiHeader.biSizeImage; // const char *bmiHeaderData = reinterpret_cast(&pBmInfo->bmiHeader); // buffer.append(bmiHeaderData); // const char *bitData = reinterpret_cast(bits.data()); // buffer.append(bitData); // const char *maskBitData = reinterpret_cast(maskBits.data()); // buffer.append(maskBitData); // DeleteObject(iconInfo.hbmMask); // DeleteObject(iconInfo.hbmColor); // DeleteDC(dc); // return true; // } void WindowFinder::sendWin32InputToFrontmostWindow(const QKeySequence &keys, const KeyEventType &type) { QVector separatedKeys; for (int i = 0; i < keys.count(); i++) { Qt::KeyboardModifiers mods = keys[0].keyboardModifiers(); if (mods & Qt::ShiftModifier) separatedKeys.append(Qt::Key_Shift); if (mods & Qt::ControlModifier) separatedKeys.append(Qt::Key_Control); if (mods & Qt::AltModifier) separatedKeys.append(Qt::Key_Alt); if (mods & Qt::MetaModifier) separatedKeys.append(Qt::Key_Meta); separatedKeys.append(keys[0].key()); } switch (type) { case KeyEventType::PRESS_AND_RELEASE: { // Send all key press events in order, then release events in reverse order, to // ensure modifier keys are released the way a user would do so on a keyboard. for (QVector::iterator keyIterator = separatedKeys.begin(); keyIterator != separatedKeys.end(); keyIterator++) { sendWin32InputEvent(*keyIterator, KeyEventType::PRESS); } for (QVector::reverse_iterator keyIterator = separatedKeys.rbegin(); keyIterator != separatedKeys.rend(); keyIterator++) { sendWin32InputEvent(*keyIterator, KeyEventType::RELEASE); } } break; default: { for (const Qt::Key &key : separatedKeys) { sendWin32InputEvent(key, type); } } break; } } void WindowFinder::sendWin32InputEvent(const Qt::Key &key, const KeyEventType &type) { INPUT input[1] = {}; ZeroMemory(input, sizeof(input)); input[0].type = INPUT_KEYBOARD; if (key >= 0x01000000 && key < 0x01000053) { input[0].ki.wVk = functionToWin32[key & 0x0000007F]; } else { input[0].ki.wVk = asciiToWin32[key & 0x0000007F]; } input[0].ki.dwFlags = type == KeyEventType::RELEASE ? KEYEVENTF_KEYUP : 0; SendInput(ARRAYSIZE(input), input, sizeof(INPUT)); } #endif // Q_OS_WIN