项目简介

这是一个复刻了小艺输入法剪切板功能的简易剪切板管理系统,解决了在 Win11 中难以查看剪切板历史记录的问题。项目围绕 C语言大作业 要求的 “增、删、改、查” 四个功能展开,依次实现。
编译环境:MSVC/GCC + mclib + Win2000 + C++11

程序简介

运行截图
image
使用方法
用户 (通过右键或快捷键等方式) 复制的内容将自动记录到程序中。用户可以通过将光标移动指定位置,并单击需要粘贴的内容,来完成粘贴。每条剪切板记录右侧两个按钮 “Mod” “X” 提供修改和删除功能。通过单击顶部标题栏下方两个按钮 “搜索” “清空” 使用查询和清空功能。
实现细节
在数据结构上,项目选择了内存管理优化过的链式循环队列。在查询方面,一开始选择了关键词提取匹配算法,但由于较为复杂编写难度大,改为使用最长公共子串模板。在 GUI 方面,使用了自己独立开发的图形库 mclib,由于是自己造的轮子,对实现细节较为熟悉,遇到问题能够快速定位解决。

完善和优化

此选题目的和初衷是为了更方便地进行复制和粘贴。
程序使用 Github 进行版本控制,并邀请了几位同学参与测试,提出了一些建议,例举部分如下:

  1. 原本软件的粘贴功能通过更新剪切板实现,但部分网址(例如:头歌等)禁止使用复制和粘贴功能。
    解决方案:通过改用 SendInput 模拟发送按键。
  2. 剪切板要修改已经复制好的内容,给出的修改框太小了,有时候不能把内容显示完全。
    解决方案:输入框独立弹出,并支持改变窗口大小。
  3. 已经复制的内容,如果下一次只复制其中一部分没办法实现,只能通过复制修改框内的内容,较为繁琐。
    解决方案:有待进一步实现。
  4. … …

源代码

main.cpp

/* main.cpp */
#include "afx.h"
int main() {
afx::startup("剪切板管理系统");
while (1) {
afx::peekmsg();
afx::print();
}
return 0;
}

afx.h

/* afx.h */
#include "mclib/src/mclib.h"
#include <string>
using namespace std;
using namespace mcl;
namespace afx {
/* gui */
void startup(char const* caption);
void peekmsg();
void print();
int print_box(point1d_t y, string str, bool isnearest);
int print_title();
double algo_lwst(wstring& a, wstring b); /* lg common substr */
void paste(std::wstring& str);
enum :int { TW = 7 };
/* data-structure */
class sys_t {
public:
/* linked-queue node */
class lqnode_t {
public:
string data;
lqnode_t* next = nullptr;
};
public:
sys_t(); /* create head node */
~sys_t(); /* release lkqueue */
bool push (string rhs); /* add node */
void pop_next(lqnode_t*& rhs);
public:
int MX = 32;
int _len = 0; /* length */
lqnode_t* _r = 0; /* rear */
lqnode_t* _f = 0; /* front */
public:
void* hwndfc = 0;
public:
lqnode_t** _pointdelete = 0;
lqnode_t** _pointed = 0;
lqnode_t** _pointmodify = 0;
lqnode_t** _pointnearest = 0;
point1d_t sw = ((TW << 2) + TW);
point1d_t sx = 0;
point1d_t sy = (TW << 1) + TW;
bool b_inempty = false;
bool b_insearch = false;
char : 8; char : 8;
};
extern sys_t sys;
}

afx.cpp

/* afx.cpp */
#include "afx.h"
#include "inputbox.h"
#include "mclib/cpp/mcl_base.h"
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#pragma warning(disable: 5039 4996)
#define WIN32_LEAN_AND_MEAN
# include <windows.h>
#undef WIN32_LEAN_AND_MEAN
namespace afx {
sys_t sys;
sys_t::sys_t()
: _r (new (std::nothrow) lqnode_t()) {
if (!_r) return;
_f = _r;
_r -> next = nullptr;
FILE* fp = 0;
fp = fopen(".bin", "r");
if (!fp) return ;
string s; int c;
while (~(c = fgetc(fp))) {
if (!c) push(s), s.clear();
else s.push_back(char(c));
}
fclose(fp);
}
sys_t::~sys_t() {
FILE* fp = 0;
fp = fopen (".bin", "w");
/* Thanks to @djw for submitting this issue! Corrected. */
while (_f) {
_r = _f;
_f = _f -> next;
delete _r;
if (_len && fp) fputs(_f->data.c_str(), fp), fputc(0, fp), --_len;
}
if (fp) fclose(fp);
_f = nullptr;
}
bool sys_t::push(string rhs) {
if (!_f) return 0;
if (_len == MX) {
/* linkedqueue is full of msg */
lqnode_t* t = _f -> next -> next;
_f -> next -> next = _r -> next;
_r -> next = _f -> next;
_r = _r -> next;
_f -> next = t;
_r -> next = nullptr;
_r -> data = rhs;
return 1;
}
if (!_r -> next) {
/* never got enough length */
lqnode_t* node = new (std::nothrow) lqnode_t();
if (!node)
return 0;
++ _len;
_r -> next = node;
_r = node;
_r -> next = nullptr;
_r -> data = rhs;
return 1;
}
/* has got enough length */
++ _len;
_r = _r -> next;
_r -> data = rhs;
return 1;
}
void sys_t::
pop_next (lqnode_t*& rhs){
-- _len;
if (rhs -> next == _r) {
_r = rhs;
return ;
}
lqnode_t* t = rhs -> next -> next;
rhs -> next -> next = _r -> next;
_r -> next = rhs -> next;
rhs -> next = t;
}
/* init window */
void startup(char const* caption) {
key.set_repeat(true);
auto size = display.get_desktop_size();
display.set_mode({ size.x / 5, size.y / 5 }, dflags.Resizable | dflags.DoubleBuf | dflags.AlphaWindow);
display.set_window_pos({ size.x - (size.x / 4), size.y - (size.y / 3) }, true);
display.set_caption(caption);
if (!display) exit(0);
display.get_surface().set_alpha(198);
display.flip();
display.get_surface().set_alpha(198);
}
/* peek msg loop */
void peekmsg() {
static tclock_t ck;
string str;
ck.tick();
HWND hwnd = ::GetForegroundWindow();
if (hwnd != display.get_wm_info()["window"])
sys.hwndfc = hwnd;
for (auto& ev : event.get()) {
switch (ev.type) {
case event.Quit: exit(0);
case event.ClipboardUpdate: {
str = event.get_details_clipboard_a();
if (str.size())
sys.push(str);
break;
}
case event.MouseWheel: {
if (ev.wheel.delta.y < 0) {
point1d_t ssm = sys.sw * sys._len - min(display.get_window_size().y - sys.sy - TW, sys.sw * sys._len);
if (sys.sx + TW <= ssm) sys.sx += TW;
else sys.sx = ssm;
}
else {
if (sys.sx - TW >= 0) sys.sx -= TW;
else sys.sx = 0;
}
break;
}
case event.KeyDown: {
if (ev.key.key == key.VkDown) {
point1d_t ssm = sys.sw * sys._len - min(display.get_window_size().y - sys.sy, sys.sw * sys._len);
if (sys.sx + TW <= ssm) sys.sx += TW;
else sys.sx = ssm;
}
if (ev.key.key == key.VkUp) {
if (sys.sx - TW >= 0) sys.sx -= TW;
else sys.sx = 0;
}
break;
}
case event.MouseButtonUp: {
if (ev.mouse.button != mouse.BtnLButton) break;
rect_t rc = display.get_window_rect();
if (afx::sys.b_inempty) {
sys._r = sys._f;
sys._len = 0;
sys._pointdelete = 0;
sys._pointed = 0;
sys._pointmodify = 0;
sys._pointnearest = 0;
}
if (afx::sys.b_insearch) {
if (!sys._len) break;
string lhs = input_box(0, const_cast<TCHAR*>(_T("查找(匹配相似度最高的元素)")), 0, rc.x, rc.y);
mcl::mcl_simpletls_ns::mcl_m2w_str_t wlhs(lhs.c_str());
wstring lwlhs = (wchar_t*)(wlhs);
if (!lhs.size()) break;
double maxn = -1, n = 0;
int i = 0, j = 0;
auto** mint = &afx::sys._f;
for (auto** it = &afx::sys._f; *it != afx::sys._r; it = &(*it)->next, j++){
mcl::mcl_simpletls_ns::mcl_m2w_str_t wrhs((*it)->next->data.c_str());
n = algo_lwst(lwlhs, wstring((wchar_t*)wrhs));
if (n >= maxn) maxn = n, mint = it, i = j;
}
if (maxn < 1) {
MessageBoxCentered(NULL, _T("什么都没有找到 QAQ\n真的,一个字都没有..."), _T("查找(匹配相似度最高的元素)"), MB_OK);
break;
}
sys._pointnearest = mint;
point1d_t y = sys.sy + (sys._len - i - 1) * sys.sw - sys.sx;
point2d_t sz = display.get_window_size();
rect_t boxrc_out = { TW, y, rc.x - TW - TW, (TW << 2) + 4 };
rect_t boxrc_in = { boxrc_out.x + 1, boxrc_out.y + 1, boxrc_out.w - 2, boxrc_out.h - 2 };
rc = {0, sys.sy, sz.x, sz.y};
if (boxrc_in.x < rc.x || boxrc_in.y < rc.y || boxrc_in.x + boxrc_in.w > rc.x + rc.w || boxrc_in.y + boxrc_in.h > rc.y + rc.h) {
sys.sx = (sys._len - i - 1) * afx::sys.sw;
point1d_t ssm = sys.sw * sys._len - min(display.get_window_size().y - sys.sy, sys.sw * sys._len);
if (sys.sx > ssm) sys.sx = ssm;
}
}
else if (sys._pointdelete) {
if (sys._pointed == sys._pointdelete) sys._pointed = 0;
if (sys._pointmodify == sys._pointdelete) sys._pointmodify = 0;
if (sys._pointnearest == sys._pointdelete) sys._pointnearest = 0;
sys.pop_next(*sys._pointdelete);
}
else if (sys._pointmodify) {
char* p = input_box(0, const_cast<TCHAR*>(_T("修改(更改指定的元素)")), const_cast<char*>((*sys._pointmodify)->next->data.c_str()), rc.x, rc.y);
if (p[0]) (*sys._pointmodify) -> next -> data = p;
}
break;
}
case event.MouseButtonDown: {
if (sys._pointed) {
if (sys.hwndfc) {
::SwitchToThisWindow(HWND(sys.hwndfc), TRUE);
mcl::mcl_simpletls_ns::mcl_m2w_str_t ws((*sys._pointed)->next->data.c_str());
wstring ws2 = static_cast<wchar_t*>(ws);
paste(ws2);
/* for (wchar_t c : ws2) */
/* ::PostMessage(HWND(sys.hwndfc), WM_IME_CHAR, c, 0); */
}
}
break;
}
}
}
}
void print() {
display.get_surface().fill(rgba(255, 222, 222, 50));
int i = 0, ret = 0;
if (afx::sys._len) {
for (auto** it = &afx::sys._f; *it != afx::sys._r; it = &(*it)->next, ++i) {
ret = afx::print_box(afx::sys.sy + (afx::sys._len - i - 1) * afx::sys.sw - afx::sys.sx, (*it)->next->data.c_str(), it == sys._pointnearest);
if (sys._pointdelete && (*it)-> next == (*sys._pointdelete) -> next && ret != 2) sys._pointdelete = 0;
else if (ret == 2) sys._pointdelete = it;
if (sys._pointed == it && ret != 1) sys._pointed = 0;
else if (ret == 1) sys._pointed = it;
if (sys._pointmodify == it && ret != 3) sys._pointmodify = 0;
else if (ret == 3) sys._pointmodify = it;
}
}
ret = afx::print_title();
afx::sys.b_inempty = ret == 1;
afx::sys.b_insearch = ret == 2;
display.flip();
}
int print_box (point1d_t y, string str, bool isnearest) {
point2d_t wndsz = display.get_window_size();
point2d_t ms = mouse.get_pos();
rect_t boxrc_out = { TW, y, wndsz.x - TW - TW, (TW << 2) + 4 };
rect_t boxrc_in = { boxrc_out.x + 1, boxrc_out.y + 1, boxrc_out.w - 2, boxrc_out.h - 2 };
rect_t boxrc = { boxrc_in.x + (TW >> 1), boxrc_in.y + 1, boxrc_in.w - (TW >> 1), boxrc_in.h - 2};
int maxl = boxrc.w / TW;
rect_t rc = boxrc_in;
int ret = (ms.x >= rc.x && ms.y > rc.y && ms.x <= rc.x + rc.w && ms.y <= rc.y + rc.h) ? 1 : 0;
display.get_surface().fill(rgba(255, 255, 66, 66), boxrc_out, blend.Alpha_rgba);
display.get_surface().fill(ret ? (isnearest ? orange : rgba(255, 255, 66, 66)) : (isnearest ? rgba(255, 66, 66, 255) : rgba(255, 181, 181, 255)), boxrc_in, blend.Alpha_rgba);
string ss;
bool spc = false, end = false;
int len = 0; bool isdbcs = false;
for (char& i : str) {
isdbcs = !isdbcs && i < 0;
if (isdbcs && (!end && len + 1 == maxl))
{ ss.push_back(' '); ++ len; }
else if (isdbcs && (end && len + 4 == maxl))
{ ss.push_back(' '); continue; }
if (len >= maxl) {
if (end) {
for (int j = len; j && j != len - 3; --j)
ss[unsigned(j)] = '.';
break;
}
ss.push_back('\n');
end = true; maxl <<= 1;
}
if (i == ' ' || i == '\t' || i == '\n' || i == '\r') {
if (!spc)
ss.push_back('`'), spc = true, ++len;
continue;
}
ss.push_back(i), spc = false, ++len;
}
font_t ft("宋体", { TW, TW << 1 });
surface_t s = ft.render(ss.c_str(), false, 0xff000000);
display.get_surface().blit(s, {boxrc.x, boxrc.y}, 0, blend.Alpha_rgba);
rect_t rc2 = { boxrc.x + boxrc.w - (TW * 3), boxrc.y + TW + 1, TW << 1, TW << 1 };
int ret2 = (ms.x >= rc2.x && ms.y > rc2.y && ms.x <= rc2.x + rc2.w && ms.y <= rc2.y + rc2.h) ? 2 : ret;
font_t ft2("宋体", { TW, TW << 1 });
s = ft2.render("×", false, ret2 == 2 ? lightblue : (ret ? 0xff000000 : 0xff444444), rgba(255, 100, 66, 166));
display.get_surface().blit(s, {rc2.x, rc2.y}, 0, blend.Alpha_rgba);
rect_t rc3 = { boxrc.x + boxrc.w - (TW * 9), boxrc.y + TW + 1, TW * 5, TW << 1 };
int ret3 = (ms.x >= rc3.x && ms.y > rc3.y && ms.x <= rc3.x + rc3.w && ms.y <= rc3.y + rc3.h) ? 3 : ret2;
font_t ft3("宋体", { TW, TW << 1 });
s = ft3.render(" Mod ", false, ret3 == 3 ? lightblue : (ret ? 0xff000000 : 0xff444444), rgba(255, 100, 66, 166));
display.get_surface().blit(s, { rc3.x, rc3.y }, 0, blend.Alpha_rgba);
return ret3;
}
int print_title() {
point2d_t ps = display.get_window_size();
point2d_t ms = mouse.get_pos();
display.get_surface().fill(rgba(255, 222, 222, 255), { 0, 0, ps.x, sys.sy - 2 });
font_t ft("宋体", { TW - 2, (TW - 2) << 1 }, true);
surface_t s = ft.render("剪切板", false, 0xff000000);
display.get_surface().blit(s, { TW + 1, TW * 2 / 3 }, 0, blend.Alpha_rgba);
string st;
stringstream ss;
ss << '(' << sys._len << '/' << sys.MX << ')';
ss >> st;
font_t ft2("宋体", { TW - 2, (TW - 2) << 1 });
s = ft2.render(st.c_str(), false, 0xff777777);
display.get_surface().blit(s, { TW + (TW * 6), TW * 2 / 3 }, 0, blend.Alpha_rgba);
rect_t rc = { ps.x - TW - 1 - (TW << 2), TW * 2 / 3, (TW - 1) << 2, (TW - 1) << 1 };
font_t ft3("宋体", { TW - 1, (TW - 1) << 1 }, true);
int ret = (ms.x >= rc.x && ms.y > rc.y && ms.x <= rc.x + rc.w && ms.y <= rc.y + rc.h) ? 1 : 0;
s = ft3.render("清空", false, ret ? aliceblue : 0xff6994a2);
display.get_surface().blit(s, {rc.x, rc.y}, 0, blend.Alpha_rgba);
rect_t rc2 = { ps.x - TW - 1 - (TW << 3) - TW, TW * 2 / 3, (TW - 1) << 2, (TW - 1) << 1};
font_t ft4("宋体", { TW - 1, (TW - 1) << 1 }, true);
int ret2 = (ms.x >= rc2.x && ms.y > rc2.y && ms.x <= rc2.x + rc2.w && ms.y <= rc2.y + rc2.h) ? 2 : ret;
s = ft4.render("搜索", false, ret2 == 2 ? aliceblue : 0xff6994a2);
display.get_surface().blit(s, {rc2.x, rc2.y}, 0, blend.Alpha_rgba);
return ret2;
}
double algo_lwst(wstring& a, wstring b){
size_t n = a.length(), m = b.length();
vector<vector<int>> arr(n, vector<int>(m));
auto fc = [](wchar_t c) {return c >= 'A' && c <= 'Z' ? c - 'A' + 'a' : c; };
for (size_t i = 0; i != n; ++ i) {
if (fc(b[0]) == fc(a[i])) arr[i][0] = int(i);
else if (i > 0) arr[i][0] = arr[i-1][0] + 1;
else arr[i][0] = 1;
}
for (size_t j = 0; j != m; ++ j) {
if (fc(a[0]) == fc(b[j])) arr[0][j] = int(j);
else if (j > 0) arr[0][j] = arr[0][j-1] + 1;
else arr[0][j] = 1;
}
for (size_t i = 1; i != n; ++i)
for (size_t j = 1; j != m; ++j) {
if (fc(a[i]) == fc(b[j])) arr[i][j] = min(arr[i-1][j]+1, min(arr[i][j-1]+1, arr[i-1][j-1]));
else arr[i][j] = min(arr[i-1][j]+1, min(arr[i][j-1]+1, arr[i-1][j-1]+1));
}
double ret = pow(.5, double(arr[n - 1][m - 1]));
for (size_t i = 0; i != n; ++ i) {
if (fc(a[i]) == fc(b[0])) arr[i][0] = 1;
else if (i != 0) arr[i][0] = arr[i-1][0];
else arr[i][0] = 0;
}
for (size_t j = 0; j != m; ++ j) {
if (fc(a[0]) == fc(b[j])) arr[0][j] = 1;
else if (j) arr[0][j] = arr[0][j-1];
else arr[0][j] = 0;
}
for (size_t i = 1; i != n; ++ i)
for (size_t j = 1; j != m; ++ j) {
if (fc(a[i]) == fc(b[j])) arr[i][j] = max(max(arr[i][j-1], arr[i-1][j]), arr[i-1][j-1]+1);
else arr[i][j] = max(max(arr[i][j-1], arr[i-1][j]), arr[i-1][j-1]);
}
ret += double(arr[n - 1][m - 1]);
return ret;
}
void paste(std::wstring &str) {
size_t len = str.length(), i = 0, idx = 0;
if (len == 0) return;
std::vector<INPUT> in(len << 1);
ZeroMemory(&in[0], in.size() * sizeof(INPUT));
while (i != len) {
WORD ch = static_cast<WORD>(str[i++]);
if (ch == 0x000A) {
in[idx].type = INPUT_KEYBOARD;
in[idx].ki.wVk = VK_RETURN;
in[idx].ki.dwFlags = 0;
++idx;
in[idx] = in[idx - 1];
in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
++idx;
continue;
}
in[idx].type = INPUT_KEYBOARD;
in[idx].ki.wScan = ch;
in[idx].ki.dwFlags = KEYEVENTF_UNICODE;
++idx;
if ((ch < 0xD800) || (ch > 0xDFFF)) {
in[idx] = in[idx - 1];
in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
++idx;
} else {
in[idx].type = INPUT_KEYBOARD;
in[idx].ki.wScan = (WORD) str[i++];
in[idx].ki.dwFlags = KEYEVENTF_UNICODE;
++idx;
in[idx] = in[idx-2];
in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
++idx;
in[idx] = in[idx-2];
in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
++idx;
}
}
SendInput(UINT(in.size()), &in[0], sizeof(INPUT));
}
}

另外,此程序中用到的 inputbox.h 代码如下:

# include "mclib/src/mclib.h"
# pragma warning(disable: 5039)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <windowsx.h>
# include <tchar.h>
# undef WIN32_LEAN_AND_MEAN
int WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HINSTANCE _hInstance;
char* _lpWndMsg, * _lpDefValue, * _lpHelpFile;
TCHAR* _lpWndTitle;
int _nHelpIndex;
HWND _hParent, _hDesktop, _hEdit, _hBtnOk, _hBtnCancel, _hBtnHelp, _hMsgText;
RECT _st_rcDesktop, _st_rcWnd;
HFONT _hWndFont;
char _lpwfn[] = "Arial";
char *_lpWndFontName = (char*)_lpwfn;
char* _szBuffer = 0; LRESULT lgt = 0;
UINT _nMaxLine = 2048-1, _nEditStyle = WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_MULTILINE | SS_LEFT; /* ES_AUTOHSCROLL */
int WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
HDC hWndDc;
WORD uBtnID;
LRESULT lpm = 12;
switch (uMsg) {
case WM_DESTROY:
if (_hWndFont) DeleteObject(_hWndFont);
PostQuitMessage(0);
break;
case WM_CREATE:
_hMsgText = CreateWindowExA(0, "Static", _lpWndMsg, WS_CHILD | WS_VISIBLE,
5, 5, 275, 70, hWnd, (HMENU)1000, _hInstance, 0);
_hBtnOk = CreateWindowExA(0, ("Button"), ("确定(&K)"),
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 285, 5, 65,
20, hWnd, (HMENU)IDOK, _hInstance, 0);
_hBtnCancel = CreateWindowExA(0, ("Button"), ("取消(&C)"), WS_CHILD | WS_VISIBLE,
285, 30, 65, 20, hWnd, (HMENU)IDCANCEL, _hInstance, 0);
_hBtnHelp = CreateWindowExA(0, ("Button"), ("帮助(&H)"), WS_CHILD | WS_VISIBLE,
285, 55, 65, 20, hWnd, (HMENU)IDHELP, _hInstance, 0);
_hEdit = CreateWindowExA(WS_EX_CLIENTEDGE, ("Edit"), _lpDefValue, _nEditStyle,
5, 5, 275, 85, hWnd, (HMENU)2000, _hInstance, 0);
/* SendMessage(_hEdit, EM_SETLIMITTEXT, _nMaxLine, 0); */
SendMessage(_hEdit, EM_SETTABSTOPS, 1, LPARAM(&lpm));
_hWndFont = CreateFontA(12, 6, 0, 0, 12, 0, 0, 0, GB2312_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH, _lpWndFontName);
if (!lstrlenA(_lpHelpFile))
ShowWindow(_hBtnHelp, SW_HIDE);
hWndDc = GetDC(hWnd);
SelectObject(hWndDc, _hWndFont);
ReleaseDC(hWnd, hWndDc);
SendDlgItemMessageA(hWnd, 1000, WM_SETFONT, WPARAM(_hWndFont), 0);
SendDlgItemMessageA(hWnd, 2000, WM_SETFONT, WPARAM(_hWndFont), 0);
SendDlgItemMessageA(hWnd, IDOK, WM_SETFONT, WPARAM(_hWndFont), 0);
SendDlgItemMessageA(hWnd, IDCANCEL, WM_SETFONT, WPARAM(_hWndFont), 0);
SendDlgItemMessageA(hWnd, IDHELP, WM_SETFONT, WPARAM(_hWndFont), 0);
break;
case WM_SIZE: /* 365,130->285,30 */
::SetWindowPos(_hBtnOk, 0, GET_X_LPARAM(lParam) - 70, 5, 65, 20, SWP_FRAMECHANGED);
::SetWindowPos(_hBtnCancel, 0, GET_X_LPARAM(lParam) - 70, 30, 65, 20, SWP_FRAMECHANGED);
::SetWindowPos(_hBtnHelp, 0, GET_X_LPARAM(lParam) - 70, 55, 65, 20, SWP_FRAMECHANGED);
::SetWindowPos(_hMsgText, 0, 5, 5, 1,1, SWP_FRAMECHANGED);
::SetWindowPos(_hEdit, 0, 5, 5, GET_X_LPARAM(lParam) - 85, GET_Y_LPARAM(lParam)-10, 0);
break;
case WM_KEYDOWN:
if (wParam == VK_RETURN)
SendMessage(hWnd, WM_COMMAND, IDOK, 0);
break;
case WM_SETFOCUS:
SetFocus(_hEdit);
break;
case WM_COMMAND:
uBtnID = LOWORD(wParam);
switch (uBtnID) {
case IDOK:
lpm = SendMessage(_hEdit, WM_GETTEXTLENGTH, 0, 0) + 10;
if (lgt < lpm) {
lgt = lpm;
delete[] _szBuffer;
_szBuffer = new(std::nothrow) char[size_t(lgt)];
}
if (_szBuffer)
GetDlgItemTextA(hWnd, 2000, _szBuffer, int(lgt));
DestroyWindow(hWnd);
break;
case IDCANCEL:
DestroyWindow(hWnd);
break;
case IDHELP:
WinHelpA(hWnd, _lpHelpFile, HELP_INDEX, ULONG_PTR(_nHelpIndex));
break;
};
break;
default:
return int(DefWindowProc(hWnd, uMsg, wParam, lParam));
}
return true;
}
char* input_box(char* lpWndMsg = NULL, TCHAR* lpWndTitle = NULL,
char* lpDefValue = NULL,
int xPos = 0, int yPos = 0, int fIsType = 0,
char* lpHelpFile = NULL, int nHelpIndex = 0)
{
if (!_szBuffer) {
_szBuffer = new(nothrow) char[1];
lgt = 1;
}
if (_szBuffer)
_szBuffer[0] = 0;
_hParent = mcl::display.get_wm_info()["window"];
_lpWndMsg = lpWndMsg;
_lpWndTitle = lpWndTitle;
_lpDefValue = lpDefValue;
_lpHelpFile = lpHelpFile;
_nHelpIndex = nHelpIndex;
if (fIsType) _nEditStyle |= fIsType;
_hInstance = GetModuleHandle(NULL);
_hDesktop = GetDesktopWindow();
GetWindowRect(_hDesktop, &_st_rcDesktop);
if (!xPos) xPos = (_st_rcDesktop.right - 365) / 2;
if (!yPos) yPos = (_st_rcDesktop.bottom - 130) / 2;
WNDCLASSEX st_WndClass;
HWND hWnd;
RtlZeroMemory(&st_WndClass, sizeof(st_WndClass));
st_WndClass.cbSize = sizeof(st_WndClass);
st_WndClass.hInstance = _hInstance;
st_WndClass.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
st_WndClass.hCursor = LoadCursor(0, IDC_ARROW);
st_WndClass.hIcon = LoadIcon(0, IDI_APPLICATION);
st_WndClass.hIconSm = st_WndClass.hIcon;
# pragma warning(push)
# pragma warning(disable: 4191)
st_WndClass.lpfnWndProc = reinterpret_cast<WNDPROC>(&WndProc);
# pragma warning(pop)
st_WndClass.lpszClassName = _T("InputBox_Class");
st_WndClass.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&st_WndClass);
hWnd = CreateWindowEx(0, _T("InputBox_Class"), _lpWndTitle,
WS_DLGFRAME | WS_SYSMENU | WS_VISIBLE | WS_THICKFRAME, xPos, yPos,
365, 130, _hParent, 0, _hInstance, 0);
MSG st_Msg;
if (!hWnd) return 0;
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
while (GetMessage(&st_Msg, 0, 0, 0)) {
if (st_Msg.message == WM_KEYDOWN)
if ((st_Msg.wParam == VK_RETURN) && (::GetAsyncKeyState(VK_CONTROL) & 0x8000))
SendMessage(hWnd, st_Msg.message, st_Msg.wParam, LPARAM(st_Msg.wParam));
TranslateMessage(&st_Msg);
DispatchMessage(&st_Msg);
}
return _szBuffer;
}
int MessageBoxCentered(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
if (!hWnd) hWnd = display.get_wm_info()["window"];
static HHOOK hHookCBT{};
hHookCBT = SetWindowsHookEx(WH_CBT,
[](int nCode, WPARAM wParam, LPARAM lParam) -> LRESULT {
if (nCode == HCBT_CREATEWND && (LPCBT_CREATEWND(lParam))->lpcs->lpszClass == reinterpret_cast<LPTSTR>(ATOM(32770))) {
RECT rcParent{};
GetWindowRect(((LPCBT_CREATEWND)lParam)->lpcs->hwndParent, &rcParent);
((LPCBT_CREATEWND)lParam)->lpcs->x = rcParent.left + ((rcParent.right - rcParent.left) - ((LPCBT_CREATEWND)lParam)->lpcs->cx) / 2;
((LPCBT_CREATEWND)lParam)->lpcs->y = rcParent.top + ((rcParent.bottom - rcParent.top) - ((LPCBT_CREATEWND)lParam)->lpcs->cy) / 2;
}
return CallNextHookEx(hHookCBT, nCode, wParam, lParam);
}, 0, GetCurrentThreadId()
);
int iRet = MessageBox(hWnd, lpText, lpCaption, uType);
UnhookWindowsHookEx(hHookCBT);
return iRet;
}

关关难过关关过,前路漫漫亦灿灿。