#include <windows.h>
#include <commctrl.h>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include "mybox.h"
LRESULT CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
bool isMinimized = true; // 窗口最小化状态
int ctrlPressCount = 0; // 记录 Ctrl 按下次数
DWORD lastCtrlPressTime = 0; // 上一次按下 Ctrl 的时间
int RePointIndex = 0; // 几乎覆盖的文本的索引
int blockHight = 30; // 块的高度
int maxRow = 15; // 最大行数
bool clipboard = true; // 剪贴板监控开关
// 系统托盘图标的通知结构
NOTIFYICONDATA nid = {0};
#define HOTKEY_ID 1 // 自定义热键 ID
#define IDC_TEXTCONTROL 2001 // 自定义文本控件 ID
HWND hDialog = NULL; // 全局变量,用于存储对话框句柄
struct ClipboardBlock
{
std::string text;
RECT rect; // 用于存储块的绘制区域
int id; // 块的唯一标识,
};
std::vector<ClipboardBlock> blocks; // 存储剪贴板块
int blockId = 1; // 初始块编号
// 创建自定义字体
HFONT hFont = CreateFont(
16, // 字体高度
0, // 字体宽度
0, // 字符旋转角度
0, // 基线旋转角度
FW_NORMAL, // 字体粗细
FALSE, // 斜体
FALSE, // 下划线
FALSE, // 删除线
ANSI_CHARSET, // 字符集
OUT_TT_PRECIS, // 输出精度
CLIP_DEFAULT_PRECIS, // 剪辑精度
DEFAULT_QUALITY, // 字体质量
FF_SWISS | DEFAULT_PITCH, // 字体族和间距
L"Arial" // 字体名称
);
// 自定义对话框创建
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
{
// 获取传递的文本
std::wstring text = reinterpret_cast<std::wstring *>(lParam)[0];
SetDlgItemTextW(hDlg, IDC_TEXTCONTROL, text.c_str());
return (INT_PTR)TRUE;
}
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
case WM_ACTIVATE:
{
// 当对话框失去焦点时关闭
if (LOWORD(wParam) == WA_INACTIVE)
{
EndDialog(hDlg, IDCANCEL);
return (INT_PTR)TRUE;
}
break;
}
}
return (INT_PTR)FALSE;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hEdit;
switch (uMsg)
{
case WM_CREATE:
{
// 调用剪贴板监听
AddClipboardFormatListener(hwnd);
break;
}
case WM_HOTKEY:
{
if (wParam == HOTKEY_ID)
{
DWORD currentTime = GetTickCount();
if (currentTime - lastCtrlPressTime <= 500)
{ // 500ms 内按下两次 Ctrl
ctrlPressCount++;
}
else
{
ctrlPressCount = 1; // 重置计数
}
lastCtrlPressTime = currentTime;
if (ctrlPressCount == 2)
{
if (isMinimized)
{
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_TOOLWINDOW); // 显示任务栏图标
ShowWindow(hwnd, SW_RESTORE); // 还原窗口
}
else
{
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_TOOLWINDOW); // 隐藏任务栏图标
ShowWindow(hwnd, SW_MINIMIZE); // 最小化窗口
}
isMinimized = !isMinimized; // 切换可见状态
ctrlPressCount = 0; // 重置计数
}
}
break;
}
case WM_CLIPBOARDUPDATE: // 监听剪贴板变化
{
if (!clipboard) // 如果监控开关为false,则不处理剪贴板变化
{
clipboard = true;
break; // 窗口不是最小化时,不处理剪贴板变化
}
if (OpenClipboard(hwnd))
{
HANDLE hData = GetClipboardData(CF_TEXT);
if (hData)
{
char *pData = static_cast<char *>(GlobalLock(hData));
if (pData)
{
// 将新的剪贴板块添加到列表
ClipboardBlock block;
block.text = pData; // 保存剪贴板内容
GlobalUnlock(hData);
// 设置块的绘制区域
if (blocks.size() < maxRow) // 如果达到了最大值
{
if (blocks.empty())
{
block.rect.top = 5; // 设置第一个块的顶部
}
else
{
block.rect.top = blocks.back().rect.bottom + 5; // 与上一个块的底部间隔
}
block.id = blockId++;
block.rect.bottom = block.rect.top + blockHight; // 每个块的高度
block.rect.left = 10;
block.rect.right = 400; // 固定宽度
blocks.push_back(block); // 添加到块列表
}
else // 如果没有达到最大值
{
blocks[RePointIndex].text = block.text; // 覆盖第n块的内容
blocks[RePointIndex].id = blockId++;
if (RePointIndex >= maxRow - 1)
{
RePointIndex = 0;
}
else
{
RePointIndex++;
}
}
// }
InvalidateRect(hwnd, NULL, TRUE); // 重新绘制窗口
}
}
CloseClipboard();
}
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HFONT oldFont = (HFONT)SelectObject(hdc, hFont);
// 绘制每个块
for (const auto &block : blocks)
{
// std::cout << block.text << std::endl;
FillRect(hdc, &block.rect, (HBRUSH)(COLOR_WINDOW + 1));
RECT rect = block.rect; // 填充块背景
// 拼接字符串
std::stringstream ss;
ss << block.id << ": " << block.text;
std::string combinedText = ss.str();
DrawTextA(hdc, combinedText.c_str(), -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER); // 绘制文本
// 绘制分割线
MoveToEx(hdc, block.rect.left, block.rect.bottom, NULL);
LineTo(hdc, block.rect.right, block.rect.bottom);
}
EndPaint(hwnd, &ps);
break;
}
case WM_LBUTTONDOWN: // 监听点击事件
{
POINT pt = {LOWORD(lParam), HIWORD(lParam)};
for (size_t i = 0; i < blocks.size(); ++i)
{
if (PtInRect(&blocks[i].rect, pt))
{
size_t len = strlen(blocks[i].text.c_str()) + 1;
HGLOBAL hClipboardData = GlobalAlloc(GMEM_DDESHARE, len);
if (hClipboardData)
{
char *pClipboardData = (char *)GlobalLock(hClipboardData);
if (pClipboardData)
{
memcpy(pClipboardData, blocks[i].text.c_str(), len);
GlobalUnlock(hClipboardData);
if (OpenClipboard(hwnd))
{
EmptyClipboard();
if (SetClipboardData(CF_TEXT, hClipboardData) == NULL)
{
// 错误处理: SetClipboardData 失败
GlobalFree(hClipboardData);
}
CloseClipboard();
}
else
{
// 错误处理: OpenClipboard 失败
GlobalFree(hClipboardData);
}
}
else
{
// 错误处理: GlobalLock 失败
GlobalFree(hClipboardData);
}
}
}
}
// 将窗口最小化,只在所有块处理完后进行
ShowWindow(hwnd, SW_MINIMIZE);
isMinimized = !isMinimized;
clipboard = false;
break;
}
case WM_RBUTTONDOWN: // 右键点击事件
{
POINT pt = {LOWORD(lParam), HIWORD(lParam)};
bool found = false;
for (size_t i = 0; i < blocks.size(); ++i)
{
if (PtInRect(&blocks[i].rect, pt))
{
//std::wstring wtext(blocks[i].text.begin(), blocks[i].text.end());
std::string message = "Clicked on block: " + blocks[i].text;
MessageBoxA(hwnd, message.c_str(), "Info", MB_OK);
break;
}
}
}
case WM_USER + 1: // 托盘图标的消息处理
switch (lParam)
{
case WM_LBUTTONDOWN:
if (isMinimized)
{
ShowWindow(hwnd, SW_RESTORE); // 单击托盘图标恢复窗口
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_TOOLWINDOW); // 恢复任务栏图标
isMinimized = false;
}
else
{
ShowWindow(hwnd, SW_HIDE); // 隐藏窗口
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_TOOLWINDOW); // 隐藏任务栏图标
isMinimized = true;
}
break;
}
break;
case WM_CLOSE:
DestroyWindow(hwnd); // 销毁窗口并发送 WM_DESTROY 消息
break;
case WM_DESTROY:
{
RemoveClipboardFormatListener(hwnd); // 移除剪贴板格式监听
PostQuitMessage(0); // 发出 WM_QUIT 消息,结束消息循环
break;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam); // 对不感兴趣的消息进行缺省处理
}
return 0;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
{
HWND blackHwnd;
blackHwnd = FindWindow(L"ConsoleWindowClass", NULL); // 处理顶级窗口的类名和窗口名称匹配指定的字符串,不搜索子窗口,将显示的黑框进行隐藏。
if (blackHwnd)
{
ShowWindow(blackHwnd, SW_HIDE); // 设置指定窗口的显示状态
}
WNDCLASS wndcls = {0}; // 创建一个窗体类
wndcls.cbClsExtra = 0; // 类的额外内存,默认为 0 即可
wndcls.cbWndExtra = 0; // 窗口的额外内存,默认为 0 即可
wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 获取画刷句柄
wndcls.hCursor = LoadCursor(NULL, IDC_CROSS); // 设置光标
wndcls.hIcon = LoadIcon(NULL, IDI_APPLICATION); // 设置窗体左上角的图标
wndcls.hInstance = hInstance; // 设置窗体所属的应用程序实例
wndcls.lpfnWndProc = WindowProc; // 设置窗体的回调函数
wndcls.lpszClassName = L"test"; // 设置窗体的类名
wndcls.lpszMenuName = NULL; // 设置窗体的菜单,没有,填 NULL
wndcls.style = CS_HREDRAW | CS_VREDRAW; // 设置窗体风格为水平重画和垂直重画
if (!RegisterClass(&wndcls))
{ // 向操作系统注册窗体
MessageBox(NULL, L"窗口类注册失败!", L"错误", MB_ICONERROR);
return 1;
}
// 设置窗口的宽度和高度
int windowWidth = 400;
int windowHeight = 600;
// 获取屏幕的宽度和高度
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
int screenHeight = GetSystemMetrics(SM_CYSCREEN);
// 计算窗口的左上角坐标,使其位于屏幕的中心
int posX = (screenWidth - windowWidth) / 2;
int posY = (screenHeight - windowHeight) / 2;
HWND hwnd = CreateWindow(L"test", L"我的编辑框",
WS_OVERLAPPEDWINDOW, posX, posY, windowWidth, windowHeight, // 宽度 高度
NULL, NULL, hInstance, NULL);
if (!RegisterHotKey(hwnd, HOTKEY_ID, MOD_CONTROL | MOD_NOREPEAT, 0))
{
MessageBox(hwnd, L"Failed to register hotkey", L"Error", MB_OK);
return 1;
}
if (!hwnd)
{ // 检查窗口创建是否成功
MessageBox(NULL, L"窗口创建失败!", L"错误", MB_ICONERROR);
return 1;
}
UpdateWindow(hwnd); // 更新窗体
isMinimized = true; // 窗口最小化状态
// SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_TOOLWINDOW); // 隐藏任务栏图标
// ShowWindow(hwnd, SW_MINIMIZE); // 最小化窗口
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd;
nid.uID = 1;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_USER + 1; // 自定义托盘消息
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcscpy_s(nid.szTip, L"我的应用程序");
Shell_NotifyIcon(NIM_ADD, &nid);
MSG msg;
// 消息循环
while (GetMessage(&msg, NULL, 0, 0))
{ // 如果消息不是 WM_QUIT, 返回非零值;如果消息是 WM_QUIT,返回零
TranslateMessage(&msg); // 翻译消息
DispatchMessage(&msg); // 派发消息
}
Shell_NotifyIcon(NIM_DELETE, &nid); // 删除托盘图标
UnregisterHotKey(hwnd, HOTKEY_ID);
return (int)msg.wParam;
}
更新:
1.为每一行数据添加了序号
2.右键点击弹出消息框显示粘贴的内容详情
task
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe build active file",
"command": "D:\\tools\\mingw64\\bin\\g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}\\${fileBasenameNoExtension}.exe",
"-lgdi32",
"-luser32",
"-municode",
"-DUNICODE",
"-D_UNICODE"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Task generated by Debugger.",
"presentation": {
"panel": "new" // 默认为“shared”表示共享,改成new之后每个进程创建新的端口
}
}
],
"version": "2.0.0"
}
launch
{
"configurations": [
{
"name": "C/C++: g++.exe build and debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "D:\\tools\\mingw64\\bin\\gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: g++.exe build active file"
}
],
"version": "2.0.0"
}