辅助摸鱼的一个小玩具——窗口透明器
窗口透明器
退役 Oier,并非专业干工程的,做得不够优秀的地方请多指教。
由 C++ 编写,用于 Windows。随便写的小玩具,也懒得大费周章上传 Github 什么的了。公布源代码,需要在自己电脑上编译一下。编译须知见后文,请务必阅读!使用说明程序里有。
作者还提供了编译好的可执行文件,如果编译报错可以选择直接下载可执行文件。如遇杀毒软件误报请信任。
:::info[编译好的程序] 通过网盘分享的文件:Transparent Window
链接: https://pan.baidu.com/s/1D8NBlL00h_1eWqPJTGPCVg?pwd=AKAK 提取码: AKAK :::
发现 BUG 可找作者私信反馈,最多大概两天会看到。
:::info[源代码]
// 禁用Windows宏冲突
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#endif
#include<bits/stdc++.h>
#include<windows.h>
// 防止Windows宏污染
#undef DELETE
#undef ERROR
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
using namespace std;
// 按键事件类型
enum class KeyEventType {
KEY_DOWN,
KEY_UP,
KEY_DOUBLE_CLICK
};
// 按键信息结构
struct KeyInfo {
int vkCode; // 虚拟键码
bool ctrlPressed; // Ctrl是否按下
bool altPressed; // Alt是否按下
bool shiftPressed; // Shift是否按下
bool winPressed; // Win键是否按下
KeyEventType eventType; // 事件类型
DWORD timestamp; // 时间戳
bool isHandled; // 是否已处理(用于阻止系统行为)
};
// 按键组合标识
struct KeyCombo {
int mainKey; // 主键
bool ctrl; // Ctrl是否按下
bool alt; // Alt是否按下
bool shift; // Shift是否按下
bool win; // Win键是否按下
// 用于map的比较
bool operator<(const KeyCombo& other) const {
if (mainKey != other.mainKey) return mainKey < other.mainKey;
if (ctrl != other.ctrl) return ctrl < other.ctrl;
if (alt != other.alt) return alt < other.alt;
if (shift != other.shift) return shift < other.shift;
return win < other.win;
}
bool operator==(const KeyCombo& other) const {
return mainKey == other.mainKey &&
ctrl == other.ctrl &&
alt == other.alt &&
shift == other.shift &&
win == other.win;
}
// 正确的组合键匹配逻辑
bool matches(int vk, bool c, bool a, bool s, bool w) const {
if (mainKey != vk) return false;
// 检查所有修饰键是否匹配
// 如果组合键要求Ctrl,则必须按下Ctrl
if (ctrl && !c) return false;
if (alt && !a) return false;
if (shift && !s) return false;
if (win && !w) return false;
// 如果组合键不要求某个修饰键,那么这个修饰键必须没有按下
if (!ctrl && c) return false;
if (!alt && a) return false;
if (!shift && s) return false;
if (!win && w) return false;
return true;
}
// 获取组合键的描述字符串
string toString() const {
string result;
if (ctrl) result += "Ctrl+";
if (alt) result += "Alt+";
if (shift) result += "Shift+";
if (win) result += "Win+";
// 获取按键名称
if (mainKey >= 'A' && mainKey <= 'Z') {
result += char(mainKey);
} else if (mainKey >= '0' && mainKey <= '9') {
result += char(mainKey);
} else {
// 特殊按键
char keyName[256] = {0};
UINT scanCode = MapVirtualKey(mainKey, MAPVK_VK_TO_VSC);
LONG lParam = (scanCode << 16);
if (GetKeyNameText(lParam, keyName, sizeof(keyName))) {
result += keyName;
} else {
char buffer[32];
snprintf(buffer, sizeof(buffer), "0x%02X", mainKey);
result += buffer;
}
}
return result;
}
};
// 为KeyCombo提供hash函数,用于unordered_map
struct KeyComboHash {
size_t operator()(const KeyCombo& k) const {
return ((hash<int>()(k.mainKey) << 4) ^ (hash<bool>()(k.ctrl) << 3) ^ (hash<bool>()(k.alt) << 2) ^
(hash<bool>()(k.shift) << 1) ^ hash<bool>()(k.win));
}
};
// 回调函数类型
using KeyCallback = function<void(const KeyInfo&)>;
// 回调函数和阻止标志
struct CallbackInfo {
KeyCallback callback;
bool blockSystemBehavior; // 是否阻止系统默认行为
};
class GlobalKeyListener {
private:
// 静态实例指针,用于钩子回调访问
static GlobalKeyListener* s_instance;
DWORD m_threadId; // 消息线程ID
HHOOK m_keyboardHook;
atomic<bool> m_isRunning;
thread m_messageThread;
// 回调函数映射
unordered_map<KeyCombo, CallbackInfo, KeyComboHash> m_keyCallbacks;
// 双击检测相关
struct KeyPressRecord {
DWORD lastPressTime;
int pressCount;
};
unordered_map<int, KeyPressRecord> m_keyPressHistory;
unordered_map<int, CallbackInfo> m_doubleClickCallbacks;
unordered_map<int, int> m_doubleClickIntervals;
// 需要阻止的组合键(用于快速检查)
unordered_set<KeyCombo, KeyComboHash> m_blockedCombos;
// 保护共享资源的互斥锁
mutable recursive_mutex m_mutex;
// 私有构造函数,使用单例模式
GlobalKeyListener() : m_keyboardHook(nullptr), m_isRunning(false) {
s_instance = this;
}
// 辅助函数:向消息线程投递消息
void PostMessageToThread(UINT msg, WPARAM wParam, LPARAM lParam) {
if (m_isRunning && m_threadId) {
PostThreadMessage(m_threadId, msg, wParam, lParam);
}
}
// 辅助函数:构建KeyInfo对象
KeyInfo MakeKeyInfo(int vkCode, KeyEventType eventType,
bool ctrl, bool alt, bool shift, bool win,
bool isHandled) const {
KeyInfo info;
info.vkCode = vkCode;
info.ctrlPressed = ctrl;
info.altPressed = alt;
info.shiftPressed = shift;
info.winPressed = win;
info.eventType = eventType;
info.timestamp = GetTickCount();
info.isHandled = isHandled;
return info;
}
// 键盘钩子处理函数(必须是静态的)
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0 && s_instance) {
KBDLLHOOKSTRUCT* kbStruct = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
int vkCode = kbStruct->vkCode;
// 获取实时按键状态
bool ctrlPressed = KEY_DOWN(VK_CONTROL);
bool altPressed = KEY_DOWN(VK_MENU);
bool shiftPressed = KEY_DOWN(VK_SHIFT);
bool winPressed = KEY_DOWN(VK_LWIN) || KEY_DOWN(VK_RWIN);
// 检查是否需要阻止此按键
bool shouldBlock = false;
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
shouldBlock = s_instance->ShouldBlockKey(vkCode, ctrlPressed, altPressed, shiftPressed, winPressed);
}
// 发送按键事件到消息线程
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
s_instance->PostKeyEvent(vkCode, KeyEventType::KEY_DOWN, ctrlPressed, altPressed, shiftPressed, winPressed, shouldBlock);
} else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
s_instance->PostKeyEvent(vkCode, KeyEventType::KEY_UP, ctrlPressed, altPressed, shiftPressed, winPressed, false);
// 双击检测(在按键释放时进行)
if (vkCode != VK_CONTROL && vkCode != VK_MENU &&
vkCode != VK_SHIFT && vkCode != VK_LWIN && vkCode != VK_RWIN) {
s_instance->PostDoubleClickCheck(vkCode, ctrlPressed, altPressed, shiftPressed, winPressed);
}
}
// 如果需要阻止,返回1表示已处理
if (shouldBlock) {
return 1;
}
}
return CallNextHookEx(nullptr, nCode, wParam, lParam);
}
// 检查是否需要阻止此按键
bool ShouldBlockKey(int vkCode, bool ctrlPressed, bool altPressed, bool shiftPressed, bool winPressed) {
lock_guard<recursive_mutex> lock(m_mutex);
for (const auto& combo : m_blockedCombos) {
if (combo.matches(vkCode, ctrlPressed, altPressed, shiftPressed, winPressed)) {
return true;
}
}
return false;
}
// 发送按键事件到消息线程
void PostKeyEvent(int vkCode, KeyEventType eventType, bool ctrlPressed, bool altPressed,
bool shiftPressed, bool winPressed, bool isHandled) {
// 打包数据
LPARAM lParam = MAKELPARAM(
(ctrlPressed ? 1 : 0) |
((altPressed ? 1 : 0) << 1) |
((shiftPressed ? 1 : 0) << 2) |
((winPressed ? 1 : 0) << 3) |
((isHandled ? 1 : 0) << 4),
vkCode
);
WPARAM wParam = static_cast<WPARAM>(eventType);
PostMessageToThread(WM_USER + 1, wParam, lParam);
}
// 发送双击检查到消息线程
void PostDoubleClickCheck(int vkCode, bool ctrlPressed, bool altPressed,
bool shiftPressed, bool winPressed) {
// 打包修饰键状态
DWORD modifiers = (ctrlPressed ? 1 : 0) |
((altPressed ? 1 : 0) << 1) |
((shiftPressed ? 1 : 0) << 2) |
((winPressed ? 1 : 0) << 3);
LPARAM lParam = MAKELPARAM(modifiers, vkCode);
PostMessageToThread(WM_USER + 2, vkCode, lParam);
}
// 处理按键事件(在消息线程中执行)
void ProcessKeyEvent(WPARAM wParam, LPARAM lParam) {
KeyEventType eventType = static_cast<KeyEventType>(wParam);
int vkCode = HIWORD(lParam);
WORD modifiers = LOWORD(lParam);
bool ctrlPressed = (modifiers & 0x01) != 0;
bool altPressed = (modifiers & 0x02) != 0;
bool shiftPressed = (modifiers & 0x04) != 0;
bool winPressed = (modifiers & 0x08) != 0;
bool isHandled = (modifiers & 0x10) != 0;
KeyInfo keyInfo = MakeKeyInfo(vkCode, eventType,
ctrlPressed, altPressed, shiftPressed, winPressed,
isHandled);
lock_guard<recursive_mutex> lock(m_mutex);
// 查找匹配的回调函数
vector<const CallbackInfo*> matchedCallbacks;
for (const auto& pair : m_keyCallbacks) {
const KeyCombo& combo = pair.first;
if (combo.matches(vkCode, ctrlPressed, altPressed, shiftPressed, winPressed)) {
matchedCallbacks.push_back(&pair.second);
}
}
// 执行回调
for (const auto& callbackInfo : matchedCallbacks) {
if (callbackInfo->callback) {
try {
callbackInfo->callback(keyInfo);
} catch (...) {
// 防止回调异常导致程序崩溃
}
}
}
}
// 处理双击检测
void ProcessDoubleClick(WPARAM wParam, LPARAM lParam) {
int vkCode = static_cast<int>(wParam);
WORD modifiers = LOWORD(lParam);
bool ctrlPressed = (modifiers & 0x01) != 0;
bool altPressed = (modifiers & 0x02) != 0;
bool shiftPressed = (modifiers & 0x04) != 0;
bool winPressed = (modifiers & 0x08) != 0;
DWORD currentTime = GetTickCount();
lock_guard<recursive_mutex> lock(m_mutex);
auto it = m_keyPressHistory.find(vkCode);
if (it != m_keyPressHistory.end()) {
DWORD lastTime = it->second.lastPressTime;
int pressCount = it->second.pressCount;
// 检查是否在双击时间间隔内
auto intervalIt = m_doubleClickIntervals.find(vkCode);
int maxInterval = (intervalIt != m_doubleClickIntervals.end()) ? intervalIt->second : 500; // 默认500ms
if ((currentTime - lastTime) <= (DWORD)maxInterval) {
pressCount++;
if (pressCount >= 2) {
// 触发双击事件
KeyInfo keyInfo = MakeKeyInfo(vkCode, KeyEventType::KEY_DOUBLE_CLICK,
ctrlPressed, altPressed, shiftPressed, winPressed,
false);
// 执行双击回调
auto callbackIt = m_doubleClickCallbacks.find(vkCode);
if (callbackIt != m_doubleClickCallbacks.end() && callbackIt->second.callback) {
try {
callbackIt->second.callback(keyInfo);
} catch (...) {
// 防止回调异常
}
}
pressCount = 0; // 重置计数
}
it->second.lastPressTime = currentTime;
it->second.pressCount = pressCount;
} else {
// 超时,重新计数
it->second.lastPressTime = currentTime;
it->second.pressCount = 1;
}
} else {
// 第一次按下
m_keyPressHistory[vkCode] = {currentTime, 1};
}
}
// 消息循环线程函数
void MessageLoop() {
m_threadId = GetCurrentThreadId();
// 安装全局键盘钩子
m_keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(nullptr), 0);
if (!m_keyboardHook) {
DWORD error = GetLastError();
system("cls");
cerr << "Failed to set keyboard hook. Error: " << error << endl;
if (error == ERROR_ACCESS_DENIED) {
cerr << "Try running the program as administrator." << endl;
}
return;
}
system("cls");
cout << "Global key listener started successfully." << endl;
// 消息循环
MSG msg;
while (m_isRunning && GetMessage(&msg, nullptr, 0, 0)) {
if (msg.message == WM_USER + 1) {
ProcessKeyEvent(msg.wParam, msg.lParam);
} else if (msg.message == WM_USER + 2) {
ProcessDoubleClick(msg.wParam, msg.lParam);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// 卸载钩子
if (m_keyboardHook) {
UnhookWindowsHookEx(m_keyboardHook);
m_keyboardHook = nullptr;
}
system("cls");
cout << "Global key listener stopped." << endl;
}
public:
// 删除复制构造函数和赋值运算符
GlobalKeyListener(const GlobalKeyListener&) = delete;
GlobalKeyListener& operator=(const GlobalKeyListener&) = delete;
// 获取单例实例
static GlobalKeyListener& GetInstance() {
static GlobalKeyListener instance;
return instance;
}
// 启动监听
bool Start() {
if (m_isRunning) return true;
m_isRunning = true;
{
lock_guard<recursive_mutex> lock(m_mutex);
m_keyPressHistory.clear();
}
try {
m_messageThread = thread(&GlobalKeyListener::MessageLoop, this);
this_thread::sleep_for(chrono::milliseconds(100));
return m_keyboardHook != nullptr;
} catch (const exception& e) {
system("cls");
cerr << "Failed to start listener: " << e.what() << endl;
m_isRunning = false;
return false;
}
}
// 停止监听
void Stop() {
if (!m_isRunning) return;
m_isRunning = false;
if (m_threadId) {
PostThreadMessage(m_threadId, WM_QUIT, 0, 0);
}
if (m_messageThread.joinable()) {
try {
m_messageThread.join();
} catch (...) {}
}
lock_guard<recursive_mutex> lock(m_mutex);
m_keyCallbacks.clear();
m_doubleClickCallbacks.clear();
m_doubleClickIntervals.clear();
m_keyPressHistory.clear();
m_blockedCombos.clear();
}
// 注册按键监听(增强版,支持阻止系统行为)
void RegisterKey(int vkCode, KeyCallback callback,
bool checkCtrl = false, bool checkAlt = false,
bool checkShift = false, bool checkWin = false,
bool blockSystemBehavior = false) {
KeyCombo combo{vkCode, checkCtrl, checkAlt, checkShift, checkWin};
CallbackInfo info{callback, blockSystemBehavior};
lock_guard<recursive_mutex> lock(m_mutex);
m_keyCallbacks[combo] = info;
if (blockSystemBehavior) {
m_blockedCombos.insert(combo);
}
}
// 注册组合键监听(增强版)
void RegisterComboKey(int mainKey, bool ctrl, bool alt, bool shift, bool win,
KeyCallback callback, bool blockSystemBehavior = false) {
RegisterKey(mainKey, callback, ctrl, alt, shift, win, blockSystemBehavior);
}
// 注册双击监听
void RegisterDoubleClick(int vkCode, int maxIntervalMs = 500,
KeyCallback callback = nullptr, bool blockSystemBehavior = false) {
lock_guard<recursive_mutex> lock(m_mutex);
m_doubleClickIntervals[vkCode] = maxIntervalMs;
if (callback) {
m_doubleClickCallbacks[vkCode] = {callback, blockSystemBehavior};
}
}
// 直接阻止组合键(无需回调)
void BlockCombo(int mainKey, bool ctrl = false, bool alt = false,
bool shift = false, bool win = false) {
KeyCombo combo{mainKey, ctrl, alt, shift, win};
lock_guard<recursive_mutex> lock(m_mutex);
m_blockedCombos.insert(combo);
}
// 解除阻止组合键
void UnblockCombo(int mainKey, bool ctrl = false, bool alt = false,
bool shift = false, bool win = false) {
KeyCombo combo{mainKey, ctrl, alt, shift, win};
lock_guard<recursive_mutex> lock(m_mutex);
m_blockedCombos.erase(combo);
}
// 移除按键监听
void UnregisterKey(int vkCode, bool ctrl = false,
bool alt = false, bool shift = false, bool win = false) {
KeyCombo combo{vkCode, ctrl, alt, shift, win};
lock_guard<recursive_mutex> lock(m_mutex);
m_keyCallbacks.erase(combo);
m_blockedCombos.erase(combo);
}
// 移除所有监听
void UnregisterAll() {
lock_guard<recursive_mutex> lock(m_mutex);
m_keyCallbacks.clear();
m_doubleClickCallbacks.clear();
m_blockedCombos.clear();
}
// 设置双击检测间隔
void SetDoubleClickInterval(int intervalMs) {
lock_guard<recursive_mutex> lock(m_mutex);
for (auto& pair : m_doubleClickIntervals) {
pair.second = intervalMs;
}
}
// 检查是否正在运行
bool IsRunning() const {
return m_isRunning;
}
// 获取当前修饰键状态(实时)
void GetModifierState(bool& ctrl, bool& alt, bool& shift, bool& win) const {
ctrl = KEY_DOWN(VK_CONTROL);
alt = KEY_DOWN(VK_MENU);
shift = KEY_DOWN(VK_SHIFT);
win = KEY_DOWN(VK_LWIN) || KEY_DOWN(VK_RWIN);
}
// 获取已注册的快捷键列表
vector<string> GetRegisteredHotkeys() const {
vector<string> hotkeys;
lock_guard<recursive_mutex> lock(m_mutex);
for (const auto& pair : m_keyCallbacks) {
hotkeys.push_back(pair.first.toString());
}
return hotkeys;
}
// 获取已阻止的快捷键列表
vector<string> GetBlockedHotkeys() const {
vector<string> hotkeys;
lock_guard<recursive_mutex> lock(m_mutex);
for (const auto& combo : m_blockedCombos) {
hotkeys.push_back(combo.toString());
}
return hotkeys;
}
// 析构函数
~GlobalKeyListener() {
Stop();
s_instance = nullptr;
}
};
// 初始化静态成员
GlobalKeyListener* GlobalKeyListener::s_instance = nullptr;
//本程序的窗口句柄
HWND myWindow;
bool isMyWinVisible = true;
//颜色常量
const int COLOR_BLACK = 0;
const int COLOR_BLUE = 1;
const int COLOR_GREEN = 2;
const int COLOR_LIGHTGREEN = 3;
const int COLOR_RED = 4;
const int COLOR_PURPLE = 5;
const int COLOR_YELLOW = 6;
const int COLOR_WHITE = 7;
const int COLOR_GREY = 8;
const int COLOR_LIGHTBLUE = 9;
const int COLOR_LIGHTGREEN2 = 10;
const int COLOR_LIGHTGREEN3 = 11;
const int COLOR_LIGHTRED = 12;
const int COLOR_LIGHTPURPLE = 13;
const int COLOR_LIGHTYELLOW = 14;
const int COLOR_LIGHTWHITE = 15;
// 宽字符输出函数封装
void WriteConStr(const wstring& str) {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD charsWritten;
WriteConsoleW(hConsole, str.c_str(), (DWORD)str.length(), &charsWritten, NULL);
}
void WriteConStr(const wchar_t* str) {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD charsWritten;
WriteConsoleW(hConsole, str, (DWORD)wcslen(str), &charsWritten, NULL);
}
//更改颜色 文字+背景
void SetColorAndBackground(int ForgC, int BackC) {
WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wColor);
return;
}
// 设置光标位置
void SetCursorPosition(int x, int y) {
COORD coord;
coord.X = (short)x;
coord.Y = (short)y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
return;
}
// 获取光标位置
void GetCursorPosition(POINT &pt) {
GetCursorPos(&pt);
ScreenToClient(myWindow, &pt);
pt.y = pt.y / 16;
pt.x = pt.x / 8;
return;
}
//设置光标可见性
void SetCursorVisibility(int x) {
CONSOLE_CURSOR_INFO cursor_info = {1, x}; // 第二个值为 0 表示隐藏光标
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
//按钮类(使用宽字符)
class Button {
public:
int x, y;
wstring name; // 改为宽字符串
int len;
// 构造函数
Button(int _x, int _y, const wstring& _name, int _len, bool isPrint = true): x(_x), y(_y), name(_name), len(_len) {
if (isPrint) {
SetCursorPosition(x, y);
WriteConStr(name);
}
}
// 输出内容
void printText() {
SetCursorPosition(x, y);
WriteConStr(name);
}
// 点击监听
bool isClicked() {
if (!isMyWinVisible || GetForegroundWindow() != myWindow) {
return 0;
}
POINT pt;
GetCursorPosition(pt);
if (KEY_DOWN(MOUSE_MOVED)) {
if (pt.y == y && (pt.x >= x && pt.x <= x + len)) {
return 1;
}
}
return 0;
}
};
// 将宽字符串转换为UTF-8字符串
string WStringToUTF8(const wstring& wstr) {
if (wstr.empty()) return string();
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
// 将系统本地编码(GBK)字符串转换为宽字符串
wstring LocalToWString(const string& local) {
if (local.empty()) return wstring();
int size_needed = MultiByteToWideChar(CP_ACP, 0, local.c_str(), (int)local.size(), NULL, 0);
wstring wstr(size_needed, 0);
MultiByteToWideChar(CP_ACP, 0, local.c_str(), (int)local.size(), &wstr[0], size_needed);
return wstr;
}
// IsWindow 检查窗口句柄是否存在
bool isHandleValid(HWND hwnd) {
return ::IsWindow(hwnd);
}
// 显示或隐藏窗口
bool SetWindowVisibility(HWND hwnd, bool visible) {
if (hwnd == NULL) return false;
if (visible) {
ShowWindow(hwnd, SW_SHOW);
SetForegroundWindow(hwnd);
} else {
ShowWindow(hwnd, SW_HIDE);
}
return true;
}
// 查询窗口透明度
int GetWindowTransparency(HWND hwnd) {
// 获取窗口扩展样式
LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
// 检查窗口是否支持分层(透明)
if (!(exStyle & WS_EX_LAYERED)) {
return 255; // 完全不透明
}
// 获取透明度值
BYTE alpha = 255;
DWORD flags;
COLORREF color;
GetLayeredWindowAttributes(hwnd, &color, &alpha, &flags);
// 如果使用Alpha值,则返回
if (flags & LWA_ALPHA) {
return (int)alpha;
}
return 255; // 没有使用Alpha透明度
}
// 设置窗口透明度 (0-255, 0=完全透明, 255=完全不透明)
bool SetWindowTransparency(HWND hwnd, int alpha) {
if (hwnd == NULL) return false;
// 设置分层窗口属性
LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
// 设置透明度
return SetLayeredWindowAttributes(hwnd, 0, (BYTE)alpha, LWA_ALPHA);
}
// 获取窗口标题(返回宽字符串)
wstring GetWindowTitleW(HWND hwnd) {
wchar_t windowTitle[1024];
GetWindowTextW(hwnd, windowTitle, 1024);
wstring res = windowTitle;
if ((int)res.size() > 33) {
res = res.substr(0, 33);
res += L"...";
}
return res;
}
// 获取窗口标题(兼容旧代码,返回UTF-8字符串)
string GetWindowTitle(HWND hwnd) {
wstring wtitle = GetWindowTitleW(hwnd);
return WStringToUTF8(wtitle);
}
//查询指定窗口是否隐藏
bool isWindowHidden(HWND hwnd) {
if (hwnd == NULL) {
return 0;
}
LONG style = GetWindowLong(hwnd, GWL_STYLE);
return (style & WS_VISIBLE) == 0;
}
//查询指定窗口是否置顶
bool IsWindowTopmost(HWND hwnd) {
LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
return (exStyle & WS_EX_TOPMOST) != 0;
}
//设置指定窗口是否置顶
void SetWindowTopmost(HWND hwnd, bool topmost) {
HWND insertAfter = topmost ? HWND_TOPMOST : HWND_NOTOPMOST;
SetWindowPos(hwnd, insertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
int deltaAlpha = 20;
vector<HWND> hiddenWindow;
bool isListen = 0;
// 给按键监听器进行实例化
GlobalKeyListener& listener = GlobalKeyListener::GetInstance();
void addListener() {
// 绑定按键监听
// Ctrl+Alt+Space 藏自己
listener.RegisterComboKey(VK_SPACE, 1, 1, 0, 0, [](const KeyInfo & info) {
if (info.eventType == KeyEventType::KEY_UP) {
if (SetWindowVisibility(myWindow, !isMyWinVisible)) {
isMyWinVisible = !isMyWinVisible;
}
}
}, 1);
// Alt+VK_RIGHT 不透明
listener.RegisterComboKey(VK_RIGHT, 0, 1, 0, 0, [](const KeyInfo & info) {
if (info.eventType == KeyEventType::KEY_UP) {
HWND nowH = GetForegroundWindow();
int nowA = GetWindowTransparency(nowH);
if (nowA > 255 - deltaAlpha) {
SetWindowTransparency(nowH, 255);
} else {
SetWindowTransparency(nowH, nowA + deltaAlpha);
}
}
}, 1);
// Alt+VK_LEFT 透明
listener.RegisterComboKey(VK_LEFT, 0, 1, 0, 0, [](const KeyInfo & info) {
if (info.eventType == KeyEventType::KEY_UP) {
HWND nowH = GetForegroundWindow();
int nowA = GetWindowTransparency(nowH);
if (nowA < 2 * deltaAlpha) {
SetWindowTransparency(nowH, deltaAlpha);
} else {
SetWindowTransparency(nowH, nowA - deltaAlpha);
}
}
}, 1);
// Ctrl+Space 隐藏
listener.RegisterComboKey(VK_SPACE, 1, 0, 0, 0, [](const KeyInfo & info) {
if (info.eventType == KeyEventType::KEY_UP) {
HWND nowH = GetForegroundWindow();
if (!isWindowHidden(nowH) && SetWindowVisibility(nowH, 0)) {
if (nowH == myWindow) {
isMyWinVisible = false;
} else {
hiddenWindow.push_back(nowH);
}
}
}
}, 1);
// Alt+VK_UP 置顶
listener.RegisterComboKey(VK_UP, 0, 1, 0, 0, [](const KeyInfo & info) {
if (info.eventType == KeyEventType::KEY_UP) {
HWND nowH = GetForegroundWindow();
SetWindowTopmost(nowH, 1);
}
}, 1);
// Alt+VK_DOWN 不置顶
listener.RegisterComboKey(VK_DOWN, 0, 1, 0, 0, [](const KeyInfo & info) {
if (info.eventType == KeyEventType::KEY_UP) {
HWND nowH = GetForegroundWindow();
SetWindowTopmost(nowH, 0);
}
}, 1);
}
//退出程序时显示所有隐藏的窗口
BOOL WINAPI ConsoleHandler(DWORD dwCtrlType) {
switch (dwCtrlType) {
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_CLOSE_EVENT:
listener.Stop();
hiddenWindow.erase(remove_if(hiddenWindow.begin(), hiddenWindow.end(), [](const HWND & nowH) {
return !isHandleValid(nowH);
}), hiddenWindow.end());
for (auto i : hiddenWindow) {
SetWindowVisibility(i, 1);
Sleep(2);
}
exit(0);
return TRUE;
default:
return FALSE;
}
}
int main() {
// 设置控制台输出编码为UTF-8(尽管我们使用WriteConsoleW,但系统命令可能需要)
// system("chcp 65001 > nul");
// 设置控制台标题为宽字符
SetConsoleTitleW(L"窗口透明器");
// 设置长宽 70 列,18 行,最好别改
system("mode con cols=70 lines=18");
system("cls");
// 尝试获取本程序的窗口句柄
try {
myWindow = GetConsoleWindow();
if (myWindow == NULL) {
// 无法获取,抛异常
throw runtime_error("无法获取窗口句柄");
}
} catch (const runtime_error& e) {
// 报错,退出程序
SetCursorPosition(0, 0);
SetColorAndBackground(COLOR_LIGHTWHITE, COLOR_RED);
WriteConStr(L"ERROR:");
SetColorAndBackground(COLOR_WHITE, COLOR_BLACK);
// 转换错误信息为宽字符
wstring errorMsg = LocalToWString(e.what());
WriteConStr(errorMsg + L"\n");
system("pause");
exit(0);
} catch (...) {
system("cls");
SetCursorPosition(0, 0);
SetColorAndBackground(COLOR_LIGHTWHITE, COLOR_RED);
WriteConStr(L"UNKNOWN ERROR");
system("pause");
exit(0);
}
hiddenWindow.clear();
// 隐藏光标
SetCursorVisibility(0);
system("cls");
// IDE 内编译警告:
SetCursorPosition(0, 0);
SetColorAndBackground(COLOR_LIGHTRED, COLOR_BLACK);
WriteConStr(L"编译完成后,请勿通过 IDE 直接运行!\n\n");
WriteConStr(L"请通过文件夹内双击程序运行!\n\n");
WriteConStr(L"如果对任务管理器等窗口不生效,请尝试用管理员身份运行!\n\n");
SetColorAndBackground(COLOR_LIGHTYELLOW, COLOR_BLACK);
WriteConStr(L"建议不要开启快速编辑模式!\n");
WriteConStr(L"否则像下面的按钮可能会无法点击!\n\n");
SetColorAndBackground(COLOR_RED, COLOR_LIGHTYELLOW);
WriteConStr(L"请不要通过 taskkill /f 关闭程序\n");
WriteConStr(L"否则隐藏的窗口将再也无法显示!\n");
SetColorAndBackground(COLOR_WHITE, COLOR_BLACK);
Button knowWarning(0, 13, L">我明白了", 9);
while (1) {
if (knowWarning.isClicked()) {
while (knowWarning.isClicked()) {
// TODO
}
break;
}
Sleep(5);
}
system("cls");
SetCursorPosition(0, 0);
// 处理强制退出(显示所有隐藏窗口并退出)
if (!SetConsoleCtrlHandler(ConsoleHandler, TRUE)) {
// 失败
SetColorAndBackground(COLOR_LIGHTYELLOW, COLOR_BLACK);
WriteConStr(L"控制台事件处理函数注册失败!\n");
WriteConStr(L"通过其他方式退出程序会使得已隐藏的窗口无法显形!\n");
WriteConStr(L"但您仍可以通过点击主页面的“退出程序”按钮退出程序,并显示所有隐藏的窗口!\n");
knowWarning.printText();
while (1) {
if (knowWarning.isClicked()) {
while (knowWarning.isClicked()) {
// TODO
}
break;
}
Sleep(5);
}
}
// 主页面
system("cls");
// 启动监听
addListener();
try {
// 失败:
if (!listener.Start()) {
throw runtime_error("无法监听按键");
} else {
isListen = 1;
}
} catch (const runtime_error& e) {
SetColorAndBackground(COLOR_LIGHTWHITE, COLOR_RED);
WriteConStr(L"\nERROR:");
SetColorAndBackground(COLOR_WHITE, COLOR_BLACK);
wstring errorMsg = LocalToWString(e.what());
WriteConStr(errorMsg + L"\n");
system("pause");
exit(0);
} catch (...) {
WriteConStr(L"\n");
SetColorAndBackground(COLOR_LIGHTWHITE, COLOR_RED);
WriteConStr(L"UNKNOWN ERROR\n");
system("pause");
exit(0);
}
system("cls");
SetColorAndBackground(COLOR_LIGHTPURPLE, COLOR_BLACK);
WriteConStr(L"窗口透明 v1.2.3\n");
SetColorAndBackground(COLOR_LIGHTGREEN, COLOR_BLACK);
Button help(0, 3, L">程序使用指南", 13);
SetColorAndBackground(COLOR_LIGHTGREEN2, COLOR_BLACK);
Button showList(0, 5, L">隐藏窗口列表", 13);
SetColorAndBackground(COLOR_LIGHTGREEN3, COLOR_BLACK);
Button getRest(0, 7, L">暂停软件功能", 13);
SetColorAndBackground(COLOR_WHITE, COLOR_BLACK);
Button leave(0, 9, L">退出程序", 29);
Button goHome(0, 17, L">返回", 5, 0);
while (1) {
if (help.isClicked()) {
system("cls");
SetCursorPosition(0, 0);
SetColorAndBackground(COLOR_PURPLE, COLOR_BLACK);
WriteConStr(L"欢迎使用本程序!\n\n");
SetColorAndBackground(COLOR_LIGHTBLUE, COLOR_BLACK);
WriteConStr(L"Alt+方向键右 可以让最前方的窗口更不透明!\n");
WriteConStr(L"Alt+方向键左 可以让最前方的窗口更透明!\n\n");
SetColorAndBackground(COLOR_LIGHTGREEN2, COLOR_BLACK);
WriteConStr(L"Ctrl+Alt+空格 可以隐藏或显示本窗口!\n\n");
SetColorAndBackground(COLOR_LIGHTRED, COLOR_BLACK);
WriteConStr(L"Ctrl+空格 可以隐藏任意窗口!\n");
WriteConStr(L"隐藏的窗口可以在主页的\"隐藏窗口列表\"中恢复!\n\n");
SetColorAndBackground(COLOR_LIGHTWHITE, COLOR_BLACK);
WriteConStr(L"Alt+方向键上 可以置顶任意窗口!\n");
WriteConStr(L"Alt+方向键下 可以取消置顶任意窗口!\n\n");
SetColorAndBackground(COLOR_LIGHTPURPLE, COLOR_BLACK);
WriteConStr(L"点击主页\"暂停/恢复软件功能\"可以开启或暂停功能!\n\n");
SetColorAndBackground(COLOR_WHITE, COLOR_GREEN);
WriteConStr(L"适当的摸鱼是为了提高效率 ^_^\n");
SetColorAndBackground(COLOR_WHITE, COLOR_BLACK);
goHome.printText();
while (1) {
if (goHome.isClicked()) {
goto HomeText;
}
Sleep(2);
}
} else if (showList.isClicked()) {
while (showList.isClicked()) {
//TODO
}
int Start = 0;
vector<Button> Items;
Button Front(0, 16, L">上一页", 7, 0);
Button Next(60, 16, L">下一页", 7, 0);
Button Renew(62, 17, L">刷新", 5, 0);
while (1) {
hiddenWindow.erase(remove_if(hiddenWindow.begin(), hiddenWindow.end(), [](const HWND & nowH) {
return !isHandleValid(nowH) || !isWindowHidden(nowH);
}), hiddenWindow.end());
if (!hiddenWindow.size()) {
Start = 0;
} else {
while (Start >= (int)hiddenWindow.size()) {
Start -= 15;
}
}
system("cls");
SetCursorPosition(0, 0);
SetColorAndBackground(COLOR_YELLOW, COLOR_BLACK);
WriteConStr(L"隐藏的窗口如下,点击显示:\n");
SetColorAndBackground(COLOR_WHITE, COLOR_BLACK);
Items.clear();
for (int i = 0; i < min(15, (int)hiddenWindow.size() - Start); i++) {
wstring n = GetWindowTitleW(hiddenWindow.at(Start + i));
if (n == L"") {
n = L"[无名窗口]";
}
// 确保显示宽度不超过70个字符
// 注意:中文和英文字符宽度不同,这里简化为字符数
Button tp(0, i + 1, n, 70, 1);
Items.push_back(tp);
}
SetColorAndBackground(COLOR_LIGHTBLUE, COLOR_BLACK);
if (Start >= 15) {
Front.printText();
}
if (Start + 15 < (int)hiddenWindow.size()) {
Next.printText();
}
SetColorAndBackground(COLOR_WHITE, COLOR_BLACK);
goHome.printText();
Renew.printText();
while (1) {
if (goHome.isClicked()) {
goto HomeText;
} else if (Start >= 15 && Front.isClicked()) {
Start -= 15;
break;
} else if (Start + 15 < (int)hiddenWindow.size() && Next.isClicked()) {
Start += 15;
break;
} else if (Renew.isClicked()) {
goto ListInner;
} else {
for (int i = 0; i < min(15, (int)Items.size()); i++) {
static HWND tp;
if (Items[i].isClicked()) {
tp = hiddenWindow.at(i + Start);
if (isHandleValid(tp)) {
SetWindowVisibility(tp, 1);
}
hiddenWindow.erase(remove(hiddenWindow.begin(), hiddenWindow.end(), tp), hiddenWindow.end());
while (Items[i].isClicked()) {
// TODO
}
goto ListInner;
}
}
}
Sleep(2);
}
ListInner:
;
}
} else if (leave.isClicked()) {
listener.Stop();
hiddenWindow.erase(remove_if(hiddenWindow.begin(), hiddenWindow.end(), [](const HWND & nowH) {
return !isHandleValid(nowH);
}), hiddenWindow.end());
for (auto i : hiddenWindow) {
SetWindowVisibility(i, 1);
Sleep(2);
}
exit(0);
} else if (goHome.isClicked()) {
while (goHome.isClicked()) {
//TODO
}
HomeText:
;
system("cls");
SetColorAndBackground(COLOR_LIGHTPURPLE, COLOR_BLACK);
WriteConStr(L"窗口透明 v1.2.3\n");
SetColorAndBackground(COLOR_LIGHTGREEN, COLOR_BLACK);
help.printText();
SetColorAndBackground(COLOR_LIGHTGREEN2, COLOR_BLACK);
showList.printText();
SetColorAndBackground(COLOR_LIGHTGREEN3, COLOR_BLACK);
getRest.printText();
SetColorAndBackground(COLOR_WHITE, COLOR_BLACK);
leave.printText();
} else if (getRest.isClicked()) {
while (getRest.isClicked()) {
//TODO
}
if (isListen) {
listener.Stop();
getRest.name = L">恢复软件功能";
isListen = 0;
} else {
if (listener.Start()) {
addListener();
getRest.name = L">暂停软件功能";
isListen = 1;
}
}
getRest.printText(); // 更新按钮显示
goto HomeText;
}
Sleep(2);
}
return 0;
}
:::
编译须知
至少需要 C++14。同时,代码大量使用宽字符,确保你的 IDE 保存代码时用的是 UTF-8 格式,编译时也是用的 UTF-8。也就是说,请你在“编译时加入下列选项”中添加:
-std=c++14 -finput-charset=UTF-8
:::error[注意] 有一条与上面很像的编译命令,为:
-fexec-charset=UTF-8
除非你知道在干什么,否则不要添加。 :::
如果希望可执行文件在不同电脑上都可以运行,请在“链接时加入下列选项”中添加:
-static
免责 & 后记
如果您选择使用本程序,那么将默认您会承担使用本程序所造成的一切后果。
作者鼓励并倡导将此程序用于正当的学习用途。如果因使用者使用不当,由此造成的一切后果作者概不负责。
作者承诺在发布代码前已经尽可能地进行了检查,但本程序仍然不能排除有存在错误与漏洞的可能。如果您发现了错误与漏洞,请尽快与作者私信反馈。如果本程序的错误与漏洞对您的电脑造成了损害,作者不承担任何责任,但会积极与您配合减小损害。
未经作者亲自许可,不得随意修改本程序的任何部分。如果未经允许随意修改本程序,由此造成的一切后果作者概不负责。
本程序有关按键监听的部分代码由 DeepSeek 编写。
Update
- upd on 2026.1.2 上午:添加暂停监听的功能;修复了“隐藏列表”会显示程序自身的问题;修复了通过本程序隐藏的窗口后来通过其他方式显示,会在列表中残留选项的问题。
- upd on 2026.1.2 下午:修复名称过长的窗口在隐藏列表中的显示问题;修复重复按 Ctrl+Space 会重复向隐藏列表中添加同一窗口的问题。
- upd on 2026.1.2 晚上:添加置顶窗口的功能;添加按钮检测的等待时间,减少 CPU 开销;添加“管理员身份”的启动提示;修复即使程序窗口不在最上层按钮也可被点击的问题;更改了调整透明度的快捷键。
- upd on 2026.1.10 晚上:使用
snprintf代替sprintf_s,增强兼容性;更改首页按钮文案;退出按钮添加使所有隐藏的窗口显形的功能,防止关闭程序后窗口再也无法显形的情况。 - upd on 2026.1.17 下午:全面使用宽字符,尽可能修复了乱码问题;缩减了监听的等待时间,提高灵敏度。
- upd on 2026.1.18 晚上:更改了编译须知。
- upd on 2026.2.14 下午:提供了编译好的程序。
- upd on 2026.2.23 中午:修复了通过其他方式关闭程序时,隐藏的窗口无法显示的问题。现在即使通过点击关闭窗口的按钮、按 Alt+F4 等手段关闭程序,也可以使隐藏的窗口显形;修改了启动提示;优化了键盘监听的代码,减少了代码长度;添加了对 Ctrl+C 的组合键监听,并尝试阻止其关闭程序的行为。
- upd on 2026.2.23 下午:紧急修复了对 Ctrl+C 的监听会阻止包括复制在内的其它系统默认行为。
- upd on 2026.2.23 晚上:修复了通过 Ctrl+C 关闭程序会让已隐藏的窗口再也无法显示的问题。如果该问题仍然出现,请确保您是通过文件夹打开的本程序,并尝试以管理员身份运行。