diff --git a/CMakeLists.txt b/CMakeLists.txt index e9d0cd4..095e4d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,12 +32,15 @@ add_subdirectory(ElaWidgetTools) # 导出src下的cpp文件 file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS src/*.cpp src/UI/*.cpp) -qt_add_executable(cbh +qt_add_executable(${PROJECT_NAME} MANUAL_FINALIZATION ${SRC_FILES} ) -target_link_libraries(cbh PRIVATE +# 添加宏定义,输出日志所处文件位置 +target_compile_definitions(${PROJECT_NAME} PRIVATE QT_MESSAGELOGCONTEXT) + +target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets Qt6::Core Qt6::Gui @@ -50,7 +53,7 @@ set(cbh_resource_files "assets/icon.png" ) -qt_add_resources(cbh "cbh" +qt_add_resources(${PROJECT_NAME} "cbh" PREFIX "/" FILES @@ -63,7 +66,7 @@ qt_add_resources(cbh "cbh" if(${QT_VERSION} VERSION_LESS 6.1.0) set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.cbh) endif() -set_target_properties(cbh PROPERTIES +set_target_properties(${PROJECT_NAME} PROPERTIES ${BUNDLE_ID_OPTION} MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} @@ -72,10 +75,10 @@ set_target_properties(cbh PROPERTIES ) include(GNUInstallDirs) -install(TARGETS cbh +install(TARGETS ${PROJECT_NAME} BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -qt_finalize_executable(cbh) +qt_finalize_executable(${PROJECT_NAME}) diff --git a/src/main.cpp b/src/main.cpp index 0839aae..d98252b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,15 +1,25 @@ #include "ElaApplication.h" -#include -#include -#include "window.h" #include "clipboard.h" +#include "winSpy.h" +#include "window.h" +#include +#include #ifdef Q_OS_WIN #include #endif int main(int argc, char *argv[]) { QApplication a(argc, argv); +// 设置消息模式:输出时间、类型、文件、行号和消息本身 +#ifdef QT_MESSAGELOGCONTEXT + qSetMessagePattern("[%{time yyyy-MM-dd HH:mm:ss.zzz}] [%{type}] %{file}:%{line} - %{message}"); +#else + qSetMessagePattern("[%{time yyyy-MM-dd HH:mm:ss.zzz}] [%{type}] - %{message}"); +#endif + // 设置监听剪贴板 ClipboardMonitor cbm(&a); + // 设置监听系统窗口焦点变化 + WinSpy spy; eApp->init(); MainWindow w; w.show(); diff --git a/src/winSpy.cpp b/src/winSpy.cpp new file mode 100644 index 0000000..5447a46 --- /dev/null +++ b/src/winSpy.cpp @@ -0,0 +1,103 @@ +#include +#include +#include + +#include "winSpy.h" + +// 全局变量,保存钩子句柄 +static HWINEVENTHOOK hook = NULL; + +// 获取窗口标题的辅助函数 +QString GetWindowTitle(HWND hwnd) { + char title[256]; + if (GetWindowTextA(hwnd, title, sizeof(title))) { + return QString(title); + } + return "Untitled"; +} + +// 获取窗口所属进程名的辅助函数 +QString GetWindowProcessName(HWND hwnd) { + DWORD processId; + GetWindowThreadProcessId(hwnd, &processId); + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); + if (hProcess) { + char processName[MAX_PATH]; + DWORD size = sizeof(processName); + if (QueryFullProcessImageNameA(hProcess, 0, processName, &size)) { + CloseHandle(hProcess); + QString fullPath(processName); + // 只返回可执行文件名称 + qsizetype lastSlash = fullPath.lastIndexOf("\\"); + if (lastSlash != -1) { + return fullPath.mid(lastSlash + 1); + } + return fullPath; + } + CloseHandle(hProcess); + } + return "Unknown"; +} + +// 事件回调函数 +void CALLBACK WinEventProc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, + DWORD dwmsEventTime) { + + // 确保事件对象是窗口且事件是前台窗口改变 + if (idObject != OBJID_WINDOW || idChild != CHILDID_SELF) { + return; + } + + if (event == EVENT_SYSTEM_FOREGROUND) { + HWND foregroundWindow = GetForegroundWindow(); // 获取当前前景窗口 + if (foregroundWindow) { + QString title = GetWindowTitle(foregroundWindow); + QString processName = GetWindowProcessName(foregroundWindow); + // 记录信息,这里示例为输出到控制台 + qDebug() << "Foreground Window Changed:"; + qDebug() << " Handle: " << foregroundWindow; + qDebug() << " Title: " << title; + qDebug() << " Process: " << processName; + qDebug() << "----------------------------------------"; + // TODO: 处理窗口数据保存 + } + } +} + +void WinSpy::setHook() { + if (hook) { + qDebug() << "Already monitoring."; + return; + } + // 设置事件钩子,监听前台窗口变化事件 + hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, // 最小事件值 + EVENT_SYSTEM_FOREGROUND, // 最大事件值 + NULL, // 钩子函数所在的DLL句柄(NULL表示当前进程) + WinEventProc, // 事件回调函数指针 + 0, // 感兴趣的进程ID(0表示所有进程) + 0, // 感兴趣的线程ID(0表示所有线程) + WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS // 标志:上下文外,跳过自身进程事件 + ); + + if (!hook) { + qWarning() << "Failed to set win event hook!"; + return; + } + qDebug() << "Start monitoring foreground window changes"; + // // 消息循环是必须的,否则回调函数不会被调用 + // MSG msg; + // while (GetMessage(&msg, NULL, 0, 0)) { + // TranslateMessage(&msg); + // DispatchMessage(&msg); + // } +} + +void WinSpy::freeHook() { + // 程序退出前卸载钩子 + if (hook) { + UnhookWinEvent(hook); + } +} + +WinSpy::WinSpy() { setHook(); } +WinSpy::~WinSpy() { freeHook(); } diff --git a/src/winSpy.h b/src/winSpy.h new file mode 100644 index 0000000..ecac86c --- /dev/null +++ b/src/winSpy.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +class WinSpy { +public: + WinSpy(); + ~WinSpy(); + +private: + void setHook(); + void freeHook(); +};