// SeeThru: make any window see-through, all the way down to 5% opacity. // Ctrl+Shift + mouse wheel over a window change that window's opacity // Ctrl+Alt+PageDown / PageUp more / less see-through (active window) // Ctrl+Alt+Home back to fully solid (active window) // Ctrl+Alt+End ghost mode: click-through and always on top #ifndef UNICODE #define UNICODE #endif #ifndef _UNICODE #define _UNICODE #endif #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x0A00 #include #include #include #include #define APP_NAME L"SeeThru" #define WM_TRAY (WM_APP + 1) #define WM_WHEELADJ (WM_APP + 2) #define MAX_ENT 128 #define MIN_PCT 5 #define STEP_PCT 5 #define HK_MORE 1 #define HK_LESS 2 #define HK_RESET 3 #define HK_GHOST 4 #define TIMER_OSD 1 #define TIMER_CLEAN 2 #define IDM_RESETALL 100 #define IDM_STARTUP 101 #define IDM_HELP 102 #define IDM_EXIT 103 #define IDM_WIN_BASE 1000 typedef struct { BOOL used; HWND h; LONG origEx; // extended style before we touched it BOOL hadLayered; // window was already layered (alpha based) BYTE origAlpha; DWORD origFlags; COLORREF origKey; int pct; // current opacity percent BOOL ghost; BOOL wasTopmost; } Ent; static Ent g_ent[MAX_ENT]; static HINSTANCE g_inst; static HWND g_main, g_osd; static HHOOK g_hook; static NOTIFYICONDATAW g_nid; static UINT g_taskbarCreated; static int g_dpi = 96; static HFONT g_osdFont; static WCHAR g_osdText[128]; static int S(int v) { return MulDiv(v, g_dpi, 96); } /* ---------------- startup setting ---------------- */ static const WCHAR *RUN_KEY = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run"; static BOOL StartupEnabled(void) { WCHAR buf[MAX_PATH * 2]; DWORD sz = sizeof(buf); return RegGetValueW(HKEY_CURRENT_USER, RUN_KEY, APP_NAME, RRF_RT_REG_SZ, NULL, buf, &sz) == ERROR_SUCCESS; } static void SetStartup(BOOL on) { HKEY k; if (RegOpenKeyExW(HKEY_CURRENT_USER, RUN_KEY, 0, KEY_WRITE, &k) != ERROR_SUCCESS) return; if (on) { WCHAR exe[MAX_PATH], val[MAX_PATH + 4]; GetModuleFileNameW(NULL, exe, MAX_PATH); swprintf(val, MAX_PATH + 4, L"\"%ls\"", exe); RegSetValueExW(k, APP_NAME, 0, REG_SZ, (BYTE *)val, (DWORD)((wcslen(val) + 1) * sizeof(WCHAR))); } else { RegDeleteValueW(k, APP_NAME); } RegCloseKey(k); } static DWORD RegGetFlag(const WCHAR *name) { DWORD v = 0, sz = sizeof(v); RegGetValueW(HKEY_CURRENT_USER, L"Software\\SeeThru", name, RRF_RT_REG_DWORD, NULL, &v, &sz); return v; } static void RegSetFlag(const WCHAR *name, DWORD v) { HKEY k; if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\SeeThru", 0, NULL, 0, KEY_WRITE, NULL, &k, NULL) == ERROR_SUCCESS) { RegSetValueExW(k, name, 0, REG_DWORD, (BYTE *)&v, sizeof(v)); RegCloseKey(k); } } /* ---------------- tray ---------------- */ static void Balloon(const WCHAR *title, const WCHAR *text) { g_nid.uFlags = NIF_INFO; wcsncpy(g_nid.szInfoTitle, title, 63); g_nid.szInfoTitle[63] = 0; wcsncpy(g_nid.szInfo, text, 255); g_nid.szInfo[255] = 0; g_nid.dwInfoFlags = NIIF_INFO; Shell_NotifyIconW(NIM_MODIFY, &g_nid); } static void AddTrayIcon(void) { ZeroMemory(&g_nid, sizeof(g_nid)); g_nid.cbSize = sizeof(g_nid); g_nid.hWnd = g_main; g_nid.uID = 1; g_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; g_nid.uCallbackMessage = WM_TRAY; g_nid.hIcon = (HICON)LoadImageW(g_inst, MAKEINTRESOURCEW(1), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); wcscpy(g_nid.szTip, L"SeeThru"); Shell_NotifyIconW(NIM_ADD, &g_nid); } /* ---------------- on-screen indicator ---------------- */ static void ShowOsd(HWND target, const WCHAR *text) { wcsncpy(g_osdText, text, 127); g_osdText[127] = 0; int w = S(220), h = S(46); RECT r; if (target && IsWindow(target) && GetWindowRect(target, &r) && r.right > r.left) { // center on the target window, clamped to its monitor HMONITOR mon = MonitorFromWindow(target, MONITOR_DEFAULTTONEAREST); MONITORINFO mi = { sizeof(mi) }; GetMonitorInfoW(mon, &mi); int cx = (r.left + r.right) / 2, cy = (r.top + r.bottom) / 2; if (cx < mi.rcWork.left + w / 2) cx = mi.rcWork.left + w / 2; if (cx > mi.rcWork.right - w / 2) cx = mi.rcWork.right - w / 2; if (cy < mi.rcWork.top + h / 2) cy = mi.rcWork.top + h / 2; if (cy > mi.rcWork.bottom - h / 2) cy = mi.rcWork.bottom - h / 2; r.left = cx - w / 2; r.top = cy - h / 2; } else { POINT p; GetCursorPos(&p); r.left = p.x - w / 2; r.top = p.y + S(24); } HRGN rgn = CreateRoundRectRgn(0, 0, w + 1, h + 1, S(12), S(12)); SetWindowRgn(g_osd, rgn, FALSE); SetWindowPos(g_osd, HWND_TOPMOST, r.left, r.top, w, h, SWP_NOACTIVATE | SWP_SHOWWINDOW); InvalidateRect(g_osd, NULL, TRUE); UpdateWindow(g_osd); SetTimer(g_main, TIMER_OSD, 1100, NULL); } static LRESULT CALLBACK OsdProc(HWND h, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_PAINT: { PAINTSTRUCT ps; HDC dc = BeginPaint(h, &ps); RECT rc; GetClientRect(h, &rc); HBRUSH bg = CreateSolidBrush(RGB(32, 36, 44)); FillRect(dc, &rc, bg); DeleteObject(bg); SelectObject(dc, g_osdFont); SetBkMode(dc, TRANSPARENT); SetTextColor(dc, RGB(255, 255, 255)); DrawTextW(dc, g_osdText, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); EndPaint(h, &ps); return 0; } case WM_MOUSEACTIVATE: return MA_NOACTIVATE; case WM_NCHITTEST: return HTTRANSPARENT; } return DefWindowProcW(h, msg, wp, lp); } /* ---------------- transparency core ---------------- */ static Ent *FindEnt(HWND h) { for (int i = 0; i < MAX_ENT; i++) if (g_ent[i].used && g_ent[i].h == h) return &g_ent[i]; return NULL; } static BOOL Allowed(HWND h) { if (!h || !IsWindow(h)) return FALSE; DWORD pid = 0; GetWindowThreadProcessId(h, &pid); if (pid == GetCurrentProcessId()) return FALSE; WCHAR cls[64]; GetClassNameW(h, cls, 64); if (!wcscmp(cls, L"Progman") || !wcscmp(cls, L"WorkerW")) return FALSE; return TRUE; } // Creates (or returns) the tracking entry. Returns NULL if the window can't be handled. static Ent *GetEnt(HWND h, const WCHAR **err) { Ent *e = FindEnt(h); if (e) return e; LONG ex = GetWindowLongW(h, GWL_EXSTYLE); BYTE a = 255; DWORD flags = 0; COLORREF key = 0; BOOL hadLayered = (ex & WS_EX_LAYERED) != 0; if (hadLayered) { if (!GetLayeredWindowAttributes(h, &key, &a, &flags)) { *err = L"This window draws its own transparency"; return NULL; } if (!(flags & LWA_ALPHA)) a = 255; } for (int i = 0; i < MAX_ENT; i++) { if (!g_ent[i].used) { e = &g_ent[i]; ZeroMemory(e, sizeof(*e)); e->used = TRUE; e->h = h; e->origEx = ex; e->hadLayered = hadLayered; e->origAlpha = a; e->origFlags = flags; e->origKey = key; e->pct = (a * 100 + 127) / 255; e->wasTopmost = (ex & WS_EX_TOPMOST) != 0; return e; } } *err = L"Too many windows"; return NULL; } static void RestoreEnt(Ent *e) { if (!e->used) return; HWND h = e->h; if (IsWindow(h)) { if (e->ghost && !e->wasTopmost) SetWindowPos(h, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); LONG cur = GetWindowLongW(h, GWL_EXSTYLE); LONG want = (cur & ~(WS_EX_LAYERED | WS_EX_TRANSPARENT)) | (e->origEx & (WS_EX_LAYERED | WS_EX_TRANSPARENT)); if (e->hadLayered) { SetWindowLongW(h, GWL_EXSTYLE, want); SetLayeredWindowAttributes(h, e->origKey, e->origAlpha, e->origFlags); } else { SetLayeredWindowAttributes(h, 0, 255, LWA_ALPHA); SetWindowLongW(h, GWL_EXSTYLE, want); } RedrawWindow(h, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN); } e->used = FALSE; } static void ApplyEnt(Ent *e) { HWND h = e->h; LONG ex = GetWindowLongW(h, GWL_EXSTYLE) | WS_EX_LAYERED; if (e->ghost) ex |= WS_EX_TRANSPARENT; else ex = (ex & ~WS_EX_TRANSPARENT) | (e->origEx & WS_EX_TRANSPARENT); SetWindowLongW(h, GWL_EXSTYLE, ex); BYTE a = (BYTE)((e->pct * 255 + 50) / 100); DWORD flags = LWA_ALPHA; if (e->hadLayered && (e->origFlags & LWA_COLORKEY)) flags |= LWA_COLORKEY; SetLayeredWindowAttributes(h, e->origKey, a, flags); } static BOOL Writable(HWND h) { // A window we can't change (admin program) silently ignores SetWindowLong. LONG ex = GetWindowLongW(h, GWL_EXSTYLE); return (ex & WS_EX_LAYERED) != 0; } static void ChangeOpacity(HWND h, int deltaPct) { if (!Allowed(h)) return; const WCHAR *err = NULL; Ent *e = GetEnt(h, &err); if (!e) { ShowOsd(h, err); return; } int pct = e->pct + deltaPct; if (pct < MIN_PCT) pct = MIN_PCT; if (pct > 100) pct = 100; e->pct = pct; if (pct >= 100 && !e->ghost) { RestoreEnt(e); ShowOsd(h, L"Opacity 100%"); return; } ApplyEnt(e); if (!Writable(h)) { e->used = FALSE; ShowOsd(h, L"Can't change this window (admin program?)"); return; } WCHAR t[64]; swprintf(t, 64, e->ghost ? L"Opacity %d%% (ghost)" : L"Opacity %d%%", pct); ShowOsd(h, t); } static void ResetWindow(HWND h) { Ent *e = FindEnt(h); if (e) RestoreEnt(e); ShowOsd(h, L"Opacity 100%"); } static void ToggleGhost(HWND h) { if (!Allowed(h)) return; const WCHAR *err = NULL; Ent *e = GetEnt(h, &err); if (!e) { ShowOsd(h, err); return; } if (!e->ghost) { e->ghost = TRUE; if (e->pct > 60) e->pct = 60; // ghosts should be see-through so you can tell ApplyEnt(e); if (!Writable(h)) { e->used = FALSE; ShowOsd(h, L"Can't change this window (admin program?)"); return; } SetWindowPos(h, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); WCHAR t[64]; swprintf(t, 64, L"Ghost mode on (%d%%)", e->pct); ShowOsd(h, t); } else { e->ghost = FALSE; if (!e->wasTopmost) SetWindowPos(h, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); if (e->pct >= 100) RestoreEnt(e); else ApplyEnt(e); ShowOsd(h, L"Ghost mode off"); } } static void ResetAll(void) { for (int i = 0; i < MAX_ENT; i++) if (g_ent[i].used) RestoreEnt(&g_ent[i]); } /* ---------------- mouse wheel hook ---------------- */ static LRESULT CALLBACK MouseLL(int code, WPARAM wp, LPARAM lp) { if (code == HC_ACTION && wp == WM_MOUSEWHEEL) { if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) && (GetAsyncKeyState(VK_SHIFT) & 0x8000) && !(GetAsyncKeyState(VK_MENU) & 0x8000)) { MSLLHOOKSTRUCT *m = (MSLLHOOKSTRUCT *)lp; HWND w = WindowFromPoint(m->pt); HWND root = w ? GetAncestor(w, GA_ROOT) : NULL; if (root) { short delta = (short)HIWORD(m->mouseData); PostMessageW(g_main, WM_WHEELADJ, (WPARAM)root, (LPARAM)delta); return 1; // swallow so the app underneath doesn't zoom or scroll } } } return CallNextHookEx(g_hook, code, wp, lp); } /* ---------------- menus ---------------- */ static void ShowHelp(void) { MessageBoxW(NULL, L"Change how see-through a window is:\n" L" Hold Ctrl+Shift and scroll the mouse wheel over any window.\n" L" Scroll down for more see-through, up for more solid.\n\n" L"Keyboard (works on the active window):\n" L" Ctrl+Alt+Page Down more see-through\n" L" Ctrl+Alt+Page Up more solid\n" L" Ctrl+Alt+Home back to fully solid\n" L" Ctrl+Alt+End ghost mode on or off\n\n" L"Ghost mode keeps the window on top of everything and lets your\n" L"clicks pass straight through it to whatever is underneath.\n" L"To turn ghost mode off, click the window's taskbar button so it\n" L"becomes active, then press Ctrl+Alt+End again. You can also pick\n" L"the window from the SeeThru tray menu to reset it.\n\n" L"Windows can go as low as 5% opacity.\n" L"Exiting SeeThru puts every window back to normal.", L"How to use SeeThru", MB_OK | MB_ICONINFORMATION); } static void ShowTrayMenu(void) { HMENU m = CreatePopupMenu(); AppendMenuW(m, MF_STRING | MF_GRAYED, 0, L"SeeThru"); AppendMenuW(m, MF_SEPARATOR, 0, NULL); int n = 0; for (int i = 0; i < MAX_ENT; i++) { Ent *e = &g_ent[i]; if (!e->used || !IsWindow(e->h)) continue; WCHAR title[80], item[128]; GetWindowTextW(e->h, title, 60); if (!title[0]) wcscpy(title, L"(untitled)"); swprintf(item, 128, L"Reset: %ls (%d%%%ls)", title, e->pct, e->ghost ? L", ghost" : L""); AppendMenuW(m, MF_STRING, IDM_WIN_BASE + i, item); n++; } if (n) AppendMenuW(m, MF_SEPARATOR, 0, NULL); AppendMenuW(m, MF_STRING | (n ? 0 : MF_GRAYED), IDM_RESETALL, L"Reset all windows"); AppendMenuW(m, MF_STRING | (StartupEnabled() ? MF_CHECKED : 0), IDM_STARTUP, L"Start with Windows"); AppendMenuW(m, MF_STRING, IDM_HELP, L"How to use"); AppendMenuW(m, MF_SEPARATOR, 0, NULL); AppendMenuW(m, MF_STRING, IDM_EXIT, L"Exit (puts windows back to normal)"); POINT p; GetCursorPos(&p); SetForegroundWindow(g_main); TrackPopupMenu(m, TPM_RIGHTBUTTON | TPM_BOTTOMALIGN, p.x, p.y, 0, g_main, NULL); PostMessageW(g_main, WM_NULL, 0, 0); DestroyMenu(m); } /* ---------------- main window ---------------- */ static LRESULT CALLBACK MainProc(HWND h, UINT msg, WPARAM wp, LPARAM lp) { if (msg == g_taskbarCreated && g_taskbarCreated) { AddTrayIcon(); return 0; } switch (msg) { case WM_TRAY: if (LOWORD(lp) == WM_RBUTTONUP || LOWORD(lp) == WM_LBUTTONUP) ShowTrayMenu(); return 0; case WM_WHEELADJ: { int notches = (int)(short)lp / WHEEL_DELTA; if (notches == 0) notches = ((short)lp > 0) ? 1 : -1; ChangeOpacity((HWND)wp, notches * STEP_PCT); // wheel up = more solid return 0; } case WM_HOTKEY: { HWND fg = GetForegroundWindow(); if (fg) fg = GetAncestor(fg, GA_ROOT); switch (wp) { case HK_MORE: ChangeOpacity(fg, -STEP_PCT); break; case HK_LESS: ChangeOpacity(fg, +STEP_PCT); break; case HK_RESET: if (Allowed(fg)) ResetWindow(fg); break; case HK_GHOST: ToggleGhost(fg); break; } return 0; } case WM_TIMER: if (wp == TIMER_OSD) { KillTimer(h, TIMER_OSD); ShowWindow(g_osd, SW_HIDE); } else if (wp == TIMER_CLEAN) { for (int i = 0; i < MAX_ENT; i++) if (g_ent[i].used && !IsWindow(g_ent[i].h)) g_ent[i].used = FALSE; } return 0; case WM_COMMAND: { UINT id = LOWORD(wp); if (id >= IDM_WIN_BASE && id < IDM_WIN_BASE + MAX_ENT) { Ent *e = &g_ent[id - IDM_WIN_BASE]; if (e->used) RestoreEnt(e); return 0; } switch (id) { case IDM_RESETALL: ResetAll(); break; case IDM_STARTUP: SetStartup(!StartupEnabled()); break; case IDM_HELP: ShowHelp(); break; case IDM_EXIT: DestroyWindow(h); break; } return 0; } case WM_QUERYENDSESSION: ResetAll(); return TRUE; case WM_DESTROY: ResetAll(); if (g_hook) UnhookWindowsHookEx(g_hook); for (int i = HK_MORE; i <= HK_GHOST; i++) UnregisterHotKey(h, i); Shell_NotifyIconW(NIM_DELETE, &g_nid); PostQuitMessage(0); return 0; } return DefWindowProcW(h, msg, wp, lp); } typedef BOOL (WINAPI *SetDpiCtxFn)(HANDLE); int WINAPI wWinMain(HINSTANCE inst, HINSTANCE prev, PWSTR cmd, int show) { (void)prev; (void)cmd; (void)show; g_inst = inst; HANDLE mutex = CreateMutexW(NULL, TRUE, L"SeeThru_SingleInstance_Mutex"); if (GetLastError() == ERROR_ALREADY_EXISTS) { MessageBoxW(NULL, L"SeeThru is already running. Look for its icon in the system tray.", APP_NAME, MB_OK | MB_ICONINFORMATION); return 0; } SetDpiCtxFn setCtx = (SetDpiCtxFn)(void *)GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetProcessDpiAwarenessContext"); if (!setCtx || !setCtx((HANDLE)-4)) SetProcessDPIAware(); HDC sdc = GetDC(NULL); g_dpi = GetDeviceCaps(sdc, LOGPIXELSY); ReleaseDC(NULL, sdc); if (g_dpi < 96) g_dpi = 96; g_osdFont = CreateFontW(-MulDiv(12, g_dpi, 72), 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH, L"Segoe UI"); WNDCLASSEXW wc; ZeroMemory(&wc, sizeof(wc)); wc.cbSize = sizeof(wc); wc.lpfnWndProc = MainProc; wc.hInstance = inst; wc.lpszClassName = L"SeeThruMain"; wc.hIcon = LoadIconW(inst, MAKEINTRESOURCEW(1)); RegisterClassExW(&wc); WNDCLASSEXW oc; ZeroMemory(&oc, sizeof(oc)); oc.cbSize = sizeof(oc); oc.lpfnWndProc = OsdProc; oc.hInstance = inst; oc.lpszClassName = L"SeeThruOSD"; oc.hCursor = LoadCursorW(NULL, IDC_ARROW); RegisterClassExW(&oc); g_main = CreateWindowExW(0, L"SeeThruMain", APP_NAME, 0, 0, 0, 0, 0, NULL, NULL, inst, NULL); g_osd = CreateWindowExW(WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_LAYERED | WS_EX_TRANSPARENT, L"SeeThruOSD", L"", WS_POPUP, 0, 0, 10, 10, NULL, NULL, inst, NULL); SetLayeredWindowAttributes(g_osd, 0, 225, LWA_ALPHA); g_taskbarCreated = RegisterWindowMessageW(L"TaskbarCreated"); AddTrayIcon(); BOOL ok = TRUE; ok &= RegisterHotKey(g_main, HK_MORE, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, VK_NEXT); ok &= RegisterHotKey(g_main, HK_LESS, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, VK_PRIOR); ok &= RegisterHotKey(g_main, HK_RESET, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, VK_HOME); ok &= RegisterHotKey(g_main, HK_GHOST, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, VK_END); g_hook = SetWindowsHookExW(WH_MOUSE_LL, MouseLL, inst, 0); SetTimer(g_main, TIMER_CLEAN, 5000, NULL); if (!RegGetFlag(L"Welcomed")) { RegSetFlag(L"Welcomed", 1); Balloon(L"SeeThru is running", L"Hold Ctrl+Shift and scroll over any window to make it see-through. Right-click this icon for more."); } else if (!ok) { Balloon(L"SeeThru", L"Some Ctrl+Alt shortcuts are taken by another program. Ctrl+Shift+scroll still works."); } MSG m; while (GetMessageW(&m, NULL, 0, 0) > 0) { TranslateMessage(&m); DispatchMessageW(&m); } if (g_osdFont) DeleteObject(g_osdFont); if (mutex) { ReleaseMutex(mutex); CloseHandle(mutex); } return 0; }