Skip to content

Commit

Permalink
feat: 根据句柄激活窗口
Browse files Browse the repository at this point in the history
  • Loading branch information
showlotus committed Sep 28, 2024
1 parent 0c7ff49 commit b676d29
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 2 deletions.
11 changes: 9 additions & 2 deletions LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,23 @@ npm install --global --production windows-build-tools@4.0.0
- [x] 100% -- 更新设置时,同步更新 `settings.json` 文件。
- [x] 100% -- 编辑 "激活热键" 时,禁用当前热键,防止误触关闭剪贴板。
- [x] 100% -- 设计数据库 API:查询、保存、删除、更新。
- [ ] 50% -- 完善监听剪贴板 SDK:监听剪贴板变化、获取当前剪贴板类型、将文件路径写入剪贴板
- [ ] 80% -- 完善监听剪贴板 SDK:监听剪贴板变化、获取当前剪贴板类型。
- [ ] 0% -- 如何检查更新,以及更新到最新版本。
- [ ] -- 记录文件的复制,并实现文件的粘贴。
- [ ] -- 图片存储空间优化,改用 Buffer 存储而不是 Base64 字符串。

## log

## 09/28

- 从剪贴板上获取到的纯文本能直接粘贴到窗口中,但是复制的文件无法粘贴到文件夹中。在考虑先不实现文件的复制了,初版只实现文本和图片的粘贴,那这样基本功能就已经实现完毕了。
- 关于活动窗口的监听,之前是想着需要开启一个线程一直监听活动窗口的变化,但其实用不着这样。在打开剪贴板之前,获取一下当前的活动窗口就可以了,记录一下窗口的句柄,若要进行粘贴操作时,根据记录的句柄重新激活该窗口,然后就是模拟粘贴操作。

## 09/24

- 昨天遇到一个问题时,当前剪贴板的来源进程是应用内部的后台进程。今天找到一个解决方案,由于只有应用进程才会有窗口,所以可以循环获取当前后台进程的父进程,直到当前进程有窗口时,说明该进程是一个应用进程。完美解决这个问题。同时还解决了系统进程无法获取到应用的问题。现在就算打开任务管理器也是能获取到应用名称的,Nice!
- TODO 不过有一个 BUG,关闭窗口时,也会触发一次剪贴板变化,不知道为啥。
- 得到应用可执行文件的路径后,可以用 `extract-file-icon` 这个包获取对应可执行文件的图标,返回的结果是一个 _Buffer_ 对象,需要转成 base64 格式。这个包是五年前的,现在依旧很坚挺
- 得到应用可执行文件的路径后,可以用 `extract-file-icon` 这个包获取对应可执行文件的图标,返回的结果是一个 _Buffer_ 对象,需要转成 base64 格式。这个包是五年前的,现在依旧很实用

## 09/21

Expand Down
195 changes: 195 additions & 0 deletions c/active-window.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <shlobj.h>

// 函数:激活指定的窗口
void ActivateWindow(HWND hwnd) {
// 检查窗口句柄是否有效
if (!IsWindow(hwnd)) {
std::cerr << "无效的窗口句柄" << std::endl;
return;
}

// 激活并聚焦窗口
SetForegroundWindow(hwnd);
SetFocus(hwnd);
std::cout << "窗口已激活" << std::endl;
}

HWND stringToHwnd(const std::string& hwndStr) {
// 将字符串转换为 unsigned long long
unsigned long long hwndInt = std::stoull(hwndStr);

// 将 unsigned long long 转换为 HWND
return reinterpret_cast<HWND>(hwndInt);
}

// 函数:聚焦并触发粘贴操作
void FocusAndPaste(HWND hwnd) {
// 检查窗口句柄是否有效
if (!IsWindow(hwnd)) {
std::cerr << "无效的窗口句柄" << std::endl;
return;
}

// 聚焦窗口
SetForegroundWindow(hwnd);
SetFocus(hwnd);

// 发送 Ctrl+V(粘贴操作)
INPUT inputs[4] = {};

// Ctrl key down
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = VK_CONTROL;

// V key down
inputs[1].type = INPUT_KEYBOARD;
inputs[1].ki.wVk = 'V';

// V key up
inputs[2].type = INPUT_KEYBOARD;
inputs[2].ki.wVk = 'V';
inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;

// Ctrl key up
inputs[3].type = INPUT_KEYBOARD;
inputs[3].ki.wVk = VK_CONTROL;
inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;

// 发送输入事件
SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));

std::cout << "粘贴操作已触发" << std::endl;
}

void PasteClipboard() {
// 模拟 Ctrl + V
keybd_event(VK_CONTROL, 0, 0, 0); // 按下 Ctrl
keybd_event(0x56, 0, 0, 0); // 按下 V
keybd_event(0x56, 0, KEYEVENTF_KEYUP, 0); // 释放 V
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0); // 释放 Ctrl
}

void SimulatePaste() {
INPUT inputs[4] = {};

// 模拟按下 Ctrl 键
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wVk = VK_CONTROL;

// 模拟按下 V 键
inputs[1].type = INPUT_KEYBOARD;
inputs[1].ki.wVk = 'V';

// 模拟释放 V 键
inputs[2].type = INPUT_KEYBOARD;
inputs[2].ki.wVk = 'V';
inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;

// 模拟释放 Ctrl 键
inputs[3].type = INPUT_KEYBOARD;
inputs[3].ki.wVk = VK_CONTROL;
inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;

// 发送输入事件
SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
}

void PostPasteMessage(HWND hwnd) {
// HWND hwnd = FindWindow("CabinetWClass", NULL);
if (hwnd) {
// 模拟 Ctrl + V 组合键
PostMessage(hwnd, WM_KEYDOWN, VK_CONTROL, 0);
PostMessage(hwnd, WM_KEYDOWN, 'V', 0);
PostMessage(hwnd, WM_KEYUP, 'V', 0);
PostMessage(hwnd, WM_KEYUP, VK_CONTROL, 0);
} else {
std::cerr << "未找到文件资源管理器窗口" << std::endl;
}
}

void SetTextToClipboard(const std::string& text) {
// 打开剪贴板
if (OpenClipboard(NULL)) {
// 清空剪贴板
EmptyClipboard();

// 分配内存并复制文本到剪贴板
HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE, text.size() + 1);
if (hGlob) {
char* pGlobal = static_cast<char*>(GlobalLock(hGlob));
memcpy(pGlobal, text.c_str(), text.size() + 1);
GlobalUnlock(hGlob);

// 将数据放入剪贴板
SetClipboardData(CF_TEXT, hGlob);
}
CloseClipboard();
}
}

void SetFilesToClipboard(const std::vector<std::string>& files) {
// 打开剪贴板
if (OpenClipboard(NULL)) {
// 清空剪贴板
EmptyClipboard();

// 分配内存以存储文件列表
size_t totalSize = 0;
for (const auto& file : files) {
totalSize += file.size() + 1; // +1 for null terminator
}

HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE, totalSize + sizeof(DROPFILES));
if (hGlob) {
DROPFILES* dropFiles = static_cast<DROPFILES*>(GlobalLock(hGlob));
dropFiles->pFiles = sizeof(DROPFILES);
dropFiles->fWide = FALSE; // 这里使用 ANSI
char* pFiles = reinterpret_cast<char*>(dropFiles + 1);
size_t offset = 0;

for (const auto& file : files) {
memcpy(pFiles + offset, file.c_str(), file.size());
offset += file.size();
pFiles[offset++] = '\0'; // null terminator
}
GlobalUnlock(hGlob);

// 将文件列表放入剪贴板
SetClipboardData(CF_HDROP, hGlob);
}
CloseClipboard();
}
}

int main() {
// 设置控制台输出为 UTF-8
SetConsoleOutputCP(CP_UTF8);

std::string hwnd_str = "459976"; // notepad
// hwnd_str = "66576"; // clash verge
// hwnd_str = "787890"; // edge
// hwnd_str = "525460"; // explorer
// hwnd_str = "52546011"; // error hwnd
HWND hwnd = stringToHwnd(hwnd_str);
std::cout << hwnd << std::endl;
std::cout << hwnd_str << std::endl;

// 写入纯文本到剪贴板
SetTextToClipboard("\nxxxx\nyyyy");

// 写入文件到剪贴板
// std::vector<std::string> files = { "C:\\Users\\showlotus\\Desktop\\WinCode\\t1.txt" };
// SetFilesToClipboard(files);

ActivateWindow(hwnd);
// Sleep(3000);
// 3 种粘贴触发方式,都无法触发文件的粘贴
// PasteClipboard();
SimulatePaste();
// PostPasteMessage(hwnd);
return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <windows.h>
#include <psapi.h>
#include <tchar.h>
#include <string>

void GetActiveWindowIconPath() {
HWND hwnd = GetForegroundWindow();
Expand Down Expand Up @@ -30,9 +31,25 @@ void GetActiveWindowIconPath() {
std::cout << "------------------------------------------" << std::endl;
}

std::string hwndToString(HWND hwnd) {
return std::to_string(reinterpret_cast<uintptr_t>(hwnd));
}

HWND stringToHwnd(const std::string& hwndStr) {
// 将字符串转换为 unsigned long long
unsigned long long hwndInt = std::stoull(hwndStr);

// 将 unsigned long long 转换为 HWND
return reinterpret_cast<HWND>(hwndInt);
}

void PrintActiveWindowTitle() {
HWND hwnd = GetForegroundWindow(); // 获取当前活动窗口的句柄
if (hwnd) {
std::string hwnd_str = hwndToString(hwnd);
std::cout << "HWND: " << hwnd << std::endl;
std::cout << "HWND string: " << hwnd_str << std::endl;
std::cout << "HWND from string: " << stringToHwnd(hwnd_str) << std::endl;
char title[256];
GetWindowText(hwnd, title, sizeof(title)); // 获取窗口标题
std::cout << "Current Active Window Title: " << title << std::endl;
Expand Down

0 comments on commit b676d29

Please sign in to comment.