使用就是打开就行,设好参数点击开始,其中设置CTRL+V会导致原本粘贴无效
04-08更新,可以记录剪贴板历史记录了,选中那一下就可以输入哪一项了

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
// 确保虚拟键码定义
#define VK_E 0x45
#define VK_Q 0x51
#define VK_V 0x56
// 定义资源标识符
#define IDC_BUTTON_START 101
#define IDC_BUTTON_STOP 102
#define IDC_EDIT_INTERVAL 103
#define IDC_COMBO_HOTKEY 104
#define IDC_LISTBOX_CLIPBOARD_RECORDS 105
#define IDC_BUTTON_DELETE 107
#define IDC_BUTTON_CLEAR 109 // 新增清空按钮ID
#define IDC_CHECKBOX_TOPMOST 108 // 复选框ID
// 定义定时器ID
#define TIMER_ID_RESET_INTERVAL 1
// 在头文件部分添加以下定义
#ifndef LB_END
#define LB_END (-1)
#endif
// 全局变量
WCHAR** g_ClipboardRecords = NULL;
int g_ClipboardRecordCount = 0;
HWND g_hListBox = NULL;
HINSTANCE g_hInst = NULL;
HHOOK g_hHook = NULL;
BOOL g_bHookInstalled = FALSE;
HWND g_hMainWnd = NULL;
int g_nInputInterval = 20; // 默认输入间隔(毫秒)
BOOL g_bTerminateInput = FALSE; // 是否终止输入标志
int g_nSelectedHotkey = 0; // 0: Ctrl+E, 1: Ctrl+Q, 2: Ctrl+V, 3: Alt+V, 4: 无快捷键
HANDLE g_hInputThread = NULL; // 输入线程句柄
WCHAR* g_pszClipboardText = NULL; // 剪贴板文本
BOOL g_bTopMost = FALSE; // 窗口是否置于顶层
// 函数声明
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void SetClipboardHook();
void RemoveClipboardHook();
void SimulateTextInput(const WCHAR* text);
void SimulateCharInput(WCHAR ch);
void CreateMainWindow();
void UpdateUIState();
DWORD WINAPI SimulateTextInputThread(LPVOID lpParam);
// DLL 入口点
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
g_hInst = (HINSTANCE)hModule;
return TRUE;
}
// 键盘钩子回调函数
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0) {
KBDLLHOOKSTRUCT* pkbllhs = (KBDLLHOOKSTRUCT*)lParam;
// 按键处理
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
BOOL bBlock = FALSE;
BOOL bAltPressed = (GetAsyncKeyState(VK_MENU) & 0x8000) != 0;
BOOL bCtrlPressed = (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;
switch (g_nSelectedHotkey) {
case 0: // Ctrl+E
if (pkbllhs->vkCode == VK_E && bCtrlPressed && !bAltPressed) {
bBlock = TRUE;
}
break;
case 1: // Ctrl+Q
if (pkbllhs->vkCode == VK_Q && bCtrlPressed && !bAltPressed) {
bBlock = TRUE;
}
break;
case 2: // Ctrl+V
if (pkbllhs->vkCode == VK_V && bCtrlPressed && !bAltPressed) {
bBlock = TRUE;
}
break;
case 3: // Alt+V
if (pkbllhs->vkCode == VK_V && bAltPressed && !bCtrlPressed) {
bBlock = TRUE;
}
break;
}
if (bBlock) {
if (g_hInputThread != NULL) {
g_bTerminateInput = TRUE; // 设置终止输入标志
} else {
// 检查剪贴板内容
if (OpenClipboard(NULL)) {
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
if (hData != NULL) {
g_pszClipboardText = (WCHAR*)GlobalLock(hData);
if (g_pszClipboardText != NULL) {
// 创建新线程模拟输入
g_hInputThread = CreateThread(NULL, 0, SimulateTextInputThread, (LPVOID)g_pszClipboardText, 0, NULL);
}
GlobalUnlock(hData);
}
CloseClipboard();
}
}
return 1; // 阻止默认处理
}
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
// 设置钩子
void SetClipboardHook() {
if (!g_bHookInstalled) {
g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, g_hInst, 0);
if (g_hHook != NULL) {
g_bHookInstalled = TRUE;
UpdateUIState();
}
}
}
// 移除钩子
void RemoveClipboardHook() {
if (g_bHookInstalled) {
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
g_bHookInstalled = FALSE;
UpdateUIState();
}
}
// 模拟输入宽字符文本
void SimulateTextInput(const WCHAR* text) {
g_bTerminateInput = FALSE; // 重置终止标志
for (const WCHAR* p = text; *p != L'' && !g_bTerminateInput; ++p) {
SimulateCharInput(*p);
Sleep(g_nInputInterval); // 使用自定义间隔
}
if (g_bTerminateInput) {
g_bTerminateInput = FALSE; // 重置标志
}
}
// 模拟宽字符输入
void SimulateCharInput(WCHAR ch) {
INPUT input[2] = {0};
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0;
input[0].ki.wScan = ch;
input[0].ki.dwFlags = KEYEVENTF_UNICODE;
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0;
input[1].ki.wScan = ch;
input[1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
SendInput(2, input, sizeof(INPUT));
}
// 创建主窗口
void CreateMainWindow() {
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hInstance = g_hInst;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = "ClipboardHookWndClass";
if (RegisterClassEx(&wc)) {
g_hMainWnd = CreateWindowEx(
0,
"ClipboardHookWndClass",
"剪贴板文本输入器2.0",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 500,
NULL,
NULL,
g_hInst,
NULL
);
if (g_hMainWnd) {
ShowWindow(g_hMainWnd, SW_SHOW);
UpdateUIState();
// 注册剪贴板更新消息
AddClipboardFormatListener(g_hMainWnd);
}
}
}
// 更新UI状态
void UpdateUIState() {
if (g_hMainWnd) {
EnableWindow(GetDlgItem(g_hMainWnd, IDC_BUTTON_START), !g_bHookInstalled);
EnableWindow(GetDlgItem(g_hMainWnd, IDC_BUTTON_STOP), g_bHookInstalled);
}
}
// 窗口过程函数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
static HBRUSH hBrush; // 背景色
static HBRUSH hButtonBrush; // 按钮颜色
static HBRUSH hButtonHoverBrush; // 按钮悬停颜色
static HBRUSH hButtonPressedBrush; // 按钮按下颜色
static HFONT hFont; // 字体
static HWND hEditInterval = NULL;
static HWND hComboHotkey = NULL;
static HWND hCheckboxTopMost = NULL;
static HWND hStartButton = NULL;
static HWND hStopButton = NULL;
static HWND hDeleteButton = NULL;
static HWND hClearButton = NULL;
switch (message) {
case WM_CREATE:
{
// 创建资源
hBrush = CreateSolidBrush(RGB(240, 240, 240));
hButtonBrush = CreateSolidBrush(RGB(64, 128, 255));
hButtonHoverBrush = CreateSolidBrush(RGB(50, 100, 200));
hButtonPressedBrush = CreateSolidBrush(RGB(40, 80, 160));
hFont = CreateFont(14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Segoe UI");
// 设置窗口背景颜色
SetClassLong(hWnd, GCL_HBRBACKGROUND, (LONG)hBrush);
// 创建控件
hStartButton = CreateWindow("BUTTON", "开启",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_FLAT,
20, 30, 80, 30, hWnd, (HMENU)IDC_BUTTON_START, g_hInst, NULL);
hStopButton = CreateWindow("BUTTON", "关闭",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_FLAT,
120, 30, 80, 30, hWnd, (HMENU)IDC_BUTTON_STOP, g_hInst, NULL);
// 创建“窗口置顶”按钮
hCheckboxTopMost = CreateWindow("BUTTON", "窗口置顶",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
220, 30, 100, 30, hWnd, (HMENU)IDC_CHECKBOX_TOPMOST, g_hInst, NULL);
hEditInterval = CreateWindow("EDIT", "50",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | ES_NUMBER | WS_EX_CLIENTEDGE,
170, 80, 140, 30, hWnd, (HMENU)IDC_EDIT_INTERVAL, g_hInst, NULL);
CreateWindow("STATIC", "输入间隔(毫秒):",
WS_VISIBLE | WS_CHILD | SS_LEFT,
20, 80, 130, 30, hWnd, NULL, g_hInst, NULL);
CreateWindow("STATIC", "快捷键(再按终止):",
WS_VISIBLE | WS_CHILD | SS_LEFT,
20, 120, 150, 100, hWnd, NULL, g_hInst, NULL);
// 创建组合框
hComboHotkey = CreateWindow("COMBOBOX", NULL,
WS_TABSTOP | WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST | WS_VSCROLL | WS_EX_CLIENTEDGE,
160, 120, 165, 100, hWnd, (HMENU)IDC_COMBO_HOTKEY, g_hInst, NULL);
// 添加组合框项
SendMessage(hComboHotkey, CB_ADDSTRING, 0, (LPARAM)"Ctrl+E");
SendMessage(hComboHotkey, CB_ADDSTRING, 0, (LPARAM)"Ctrl+Q");
SendMessage(hComboHotkey, CB_ADDSTRING, 0, (LPARAM)"Ctrl+V");
SendMessage(hComboHotkey, CB_ADDSTRING, 0, (LPARAM)"Alt+V");
SendMessage(hComboHotkey, CB_ADDSTRING, 0, (LPARAM)"无快捷键");
SendMessage(hComboHotkey, CB_SETCURSEL, 0, 0); // 默认选择第一个
// 设置定时器,在10毫秒后触发
SetTimer(hWnd, TIMER_ID_RESET_INTERVAL, 10, NULL);
// 创建列表框
g_hListBox = CreateWindow("LISTBOX", NULL,
WS_TABSTOP | WS_VISIBLE | WS_CHILD | LBS_STANDARD,
20, 160, 360, 280, hWnd, (HMENU)IDC_LISTBOX_CLIPBOARD_RECORDS, g_hInst, NULL);
// 创建删除按钮
hDeleteButton = CreateWindow("BUTTON", "删除",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_FLAT,
120, 430, 80, 30, hWnd, (HMENU)IDC_BUTTON_DELETE, g_hInst, NULL);
// 创建清空按钮
hClearButton = CreateWindow("BUTTON", "清空",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_FLAT,
220, 430, 80, 30, hWnd, (HMENU)IDC_BUTTON_CLEAR, g_hInst, NULL);
// 设置字体
// 创建放大一倍的字体
HFONT hBigFont = CreateFont(28, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Segoe UI");
SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
SendMessage(hStartButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
SendMessage(hStopButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
SendMessage(hEditInterval, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
SendMessage(hComboHotkey, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
SendMessage(g_hListBox, WM_SETFONT, (WPARAM)hBigFont, MAKELPARAM(TRUE, 0));
SendMessage(hDeleteButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
SendMessage(hClearButton, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
SendMessage(hCheckboxTopMost, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
UpdateUIState();
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// 绘制按钮背景
RECT rect;
GetClientRect(hWnd, &rect);
// 绘制窗口背景
FillRect(hdc, &rect, hBrush);
// 绘制按钮
GetClientRect(hStartButton, &rect);
OffsetRect(&rect, 20, 30);
FillRect(hdc, &rect, hButtonBrush);
GetClientRect(hStopButton, &rect);
OffsetRect(&rect, 120, 30);
FillRect(hdc, &rect, hButtonBrush);
GetClientRect(hDeleteButton, &rect);
OffsetRect(&rect, 120, 320);
FillRect(hdc, &rect, hButtonBrush);
GetClientRect(hClearButton, &rect);
OffsetRect(&rect, 220, 320);
FillRect(hdc, &rect, hButtonBrush);
// 绘制复选框背景
GetClientRect(hCheckboxTopMost, &rect);
OffsetRect(&rect, 220, 30);
FillRect(hdc, &rect, hBrush);
EndPaint(hWnd, &ps);
break;
}
case WM_CLIPBOARDUPDATE:
{
if (OpenClipboard(NULL)) {
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
if (hData != NULL) {
WCHAR* text = (WCHAR*)GlobalLock(hData);
if (text != NULL) {
// 检查内容是否已在列表中
BOOL found = FALSE;
int index = -1;
for (int i = 0; i < g_ClipboardRecordCount; i++) {
if (wcscmp(g_ClipboardRecords[i], text) == 0) {
found = TRUE;
index = i;
break;
}
}
if (found) {
// 将该项移到最前面
WCHAR* temp = g_ClipboardRecords[index];
for (int i = index; i > 0; i--) {
g_ClipboardRecords[i] = g_ClipboardRecords[i - 1];
}
g_ClipboardRecords[0] = temp;
// 更新列表框
SendMessageW(g_hListBox, LB_DELETESTRING, index, 0);
SendMessageW(g_hListBox, LB_INSERTSTRING, (WPARAM)0, (LPARAM)temp);
SendMessageW(g_hListBox, LB_SETCURSEL, 0, 0);
} else {
// 添加新项到末尾
WCHAR* newText = _wcsdup(text);
if (newText != NULL) {
// 动态调整记录数组的大小
g_ClipboardRecords = (WCHAR**)realloc(g_ClipboardRecords, (g_ClipboardRecordCount + 1) * sizeof(WCHAR*));
if (g_ClipboardRecords != NULL) {
g_ClipboardRecords[g_ClipboardRecordCount] = newText;
g_ClipboardRecordCount++;
// 将新项移到最前面
for (int i = g_ClipboardRecordCount - 1; i > 0; i--) {
g_ClipboardRecords[i] = g_ClipboardRecords[i - 1];
}
g_ClipboardRecords[0] = newText;
// 更新列表框
SendMessageW(g_hListBox, LB_INSERTSTRING, (WPARAM)0, (LPARAM)newText);
SendMessageW(g_hListBox, LB_SETCURSEL, 0, 0);
}
}
}
GlobalUnlock(hData);
}
}
CloseClipboard();
}
break;
}
case WM_CTLCOLORSTATIC:
{
HDC hdc = (HDC)wParam;
HWND hwndStatic = (HWND)lParam;
// 设置背景颜色为浅灰色
SetBkColor(hdc, RGB(240, 240, 240));
SetTextColor(hdc, RGB(0, 0, 0)); // 设置文本颜色为黑色
return (LRESULT)GetStockObject(NULL_BRUSH);
}
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
if (wmId == IDC_BUTTON_START) {
SetClipboardHook();
} else if (wmId == IDC_BUTTON_STOP) {
RemoveClipboardHook();
} else if (wmId == IDC_EDIT_INTERVAL) {
if (HIWORD(wParam) == EN_CHANGE) {
char buffer[32];
GetWindowTextA(hEditInterval, buffer, 32);
g_nInputInterval = atoi(buffer);
}
} else if (wmId == IDC_COMBO_HOTKEY) {
if (HIWORD(wParam) == CBN_SELCHANGE) {
int index = SendMessageW(hComboHotkey, CB_GETCURSEL, 0, 0);
g_nSelectedHotkey = index;
}
} else if (wmId == IDC_BUTTON_DELETE) {
int index = SendMessageW(g_hListBox, LB_GETCURSEL, 0, 0);
if (index != LB_ERR) {
free(g_ClipboardRecords[index]);
for (int i = index; i < g_ClipboardRecordCount - 1; i++) {
g_ClipboardRecords[i] = g_ClipboardRecords[i + 1];
}
g_ClipboardRecordCount--;
SendMessageW(g_hListBox, LB_DELETESTRING, index, 0);
// 删除后,重新设置选中项
if (g_ClipboardRecordCount > 0) {
int newIndex = min(index, g_ClipboardRecordCount - 1);
SendMessageW(g_hListBox, LB_SETCURSEL, newIndex, 0);
}
}
} else if (wmId == IDC_BUTTON_CLEAR) {
// 清空列表
for (int i = 0; i < g_ClipboardRecordCount; i++) {
free(g_ClipboardRecords[i]);
}
free(g_ClipboardRecords);
g_ClipboardRecords = NULL;
g_ClipboardRecordCount = 0;
SendMessageW(g_hListBox, LB_RESETCONTENT, 0, 0);
} else if (wmId == IDC_LISTBOX_CLIPBOARD_RECORDS) {
if (HIWORD(wParam) == LBN_SELCHANGE) {
int index = SendMessageW(g_hListBox, LB_GETCURSEL, 0, 0);
if (index != LB_ERR && g_ClipboardRecords[index] != NULL) {
// 将选中项写入剪贴板
if (OpenClipboard(NULL)) {
EmptyClipboard();
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, (wcslen(g_ClipboardRecords[index]) + 1) * sizeof(WCHAR));
if (hMem) {
WCHAR* pText = (WCHAR*)GlobalLock(hMem);
wcscpy(pText, g_ClipboardRecords[index]);
GlobalUnlock(hMem);
SetClipboardData(CF_UNICODETEXT, hMem);
}
CloseClipboard();
}
}
}
} else if (wmId == IDC_CHECKBOX_TOPMOST) {
if (HIWORD(wParam) == BN_CLICKED) {
g_bTopMost = IsDlgButtonChecked(hWnd, IDC_CHECKBOX_TOPMOST);
SetWindowPos(hWnd, g_bTopMost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}
}
break;
}
case WM_TIMER:
{
if (wParam == TIMER_ID_RESET_INTERVAL) {
// 停止定时器
KillTimer(hWnd, TIMER_ID_RESET_INTERVAL);
// 将输入间隔改回10
g_nInputInterval = 10;
// 更新编辑框的显示
char buffer[32];
sprintf(buffer, "%d", g_nInputInterval);
SetWindowText(hEditInterval, buffer);
}
break;
}
case WM_CLOSE:
RemoveClipboardHook();
DestroyWindow(hWnd);
break;
case WM_DESTROY:
{
// 释放资源
DeleteObject(hBrush);
DeleteObject(hButtonBrush);
DeleteObject(hButtonHoverBrush);
DeleteObject(hButtonPressedBrush);
DeleteObject(hFont);
for (int i = 0; i < g_ClipboardRecordCount; i++) {
free(g_ClipboardRecords[i]);
}
free(g_ClipboardRecords);
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// 主函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
CreateMainWindow();
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// 模拟输入线程函数
DWORD WINAPI SimulateTextInputThread(LPVOID lpParam) {
SimulateTextInput((WCHAR*)lpParam);
g_hInputThread = NULL;
return 0;
}
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END



















- 最新
- 最热
只看作者