#pragma comment(lib, "comctl32.lib") // for visual styles #pragma comment(lib, "kernel32.lib") // for visual styles #pragma comment(linker, "/manifestdependency:\"type='win32' \ name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \ language='*'\"") #include #include #define ID_HOTKEY_UP 200 #define ID_HOTKEY_LEFT 300 #define ID_HOTKEY_RIGHT 400 #include #include #define TRACE(...) \ do{ \ char *__trace = NULL; \ int len = 1+_scprintf(__VA_ARGS__); \ __trace = (char*)malloc(len*sizeof(char)); \ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); \ sprintf_s(__trace, len, __VA_ARGS__); \ _RPT0(_CRT_WARN, __trace); \ if(__trace != NULL) \ free(__trace); \ } while(0) typedef struct { UINT uNumWindows; UINT uListLength; UINT uCurrent; HWND* list; } WindowList; typedef DWORD (WINAPI *PSLWA)(HWND, DWORD, BYTE, DWORD); PSLWA pSetLayeredWindowAttributes = NULL; HWND g_hwndMain; HHOOK g_hHookKeyboard = NULL; void ClearWindowList(WindowList* wl) { if(wl->list != NULL) free(wl->list); wl->list = NULL; wl->uListLength = 0; wl->uNumWindows = 0; wl->uCurrent = 0; } void EnableWindowAlpha(HWND hwnd) { SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); } void DisableWindowAlpha(HWND hwnd) { SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED); } void SetWindowAlpha(HWND hwnd, BYTE alpha) { // assumes that EnableWindowAlpha has already been called if(pSetLayeredWindowAttributes == NULL) return; pSetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA); } void MultiDisableWindowAlpha(WindowList wl) { UINT i; for(i = 0; i < wl.uNumWindows; ++i) DisableWindowAlpha(wl.list[i]); } void MultiSetWindowAlpha(WindowList wl, BYTE alpha) { UINT i; for(i = 0; i < wl.uNumWindows; ++i) { EnableWindowAlpha(wl.list[i]); SetWindowAlpha(wl.list[i], alpha); } } void PrintWindowTitle(HWND hwnd) { char title[256]; GetWindowText(hwnd, title, 256); TRACE("Window: %s\n", title); } BOOL IsAltTabWindow(HWND hwnd) { TITLEBARINFO ti; HWND hwndTry, hwndWalk = NULL; if(!IsWindowVisible(hwnd)) return FALSE; hwndTry = GetAncestor(hwnd, GA_ROOTOWNER); while(hwndTry != hwndWalk) { hwndWalk = hwndTry; hwndTry = GetLastActivePopup(hwndWalk); if(IsWindowVisible(hwndTry)) break; } if(hwndWalk != hwnd) return FALSE; // the following removes some task tray programs and "Program Manager" ti.cbSize = sizeof(ti); GetTitleBarInfo(hwnd, &ti); if(ti.rgstate[0] & STATE_SYSTEM_INVISIBLE) return FALSE; return TRUE; } BOOL CALLBACK EnumVisibleWindowsProc(HWND hwnd, LPARAM lParam) { // return TRUE to continue enumeration, FALSE to stop WindowList* lpwl = (WindowList*)lParam; if(!IsAltTabWindow(hwnd) || IsIconic(hwnd)) return TRUE; // skip this window and continue if(lpwl->uNumWindows < lpwl->uListLength) lpwl->list[lpwl->uNumWindows] = hwnd; else return FALSE; //PrintWindowTitle(hwnd); lpwl->uNumWindows++; return TRUE; } BOOL CALLBACK EnumMinimizedWindowsProc(HWND hwnd, LPARAM lParam) { // return TRUE to continue enumeration, FALSE to stop WindowList* lpwl = (WindowList*)lParam; if(!IsAltTabWindow(hwnd) || !IsIconic(hwnd)) return TRUE; // skip this window and continue if(lpwl->uNumWindows < lpwl->uListLength) lpwl->list[lpwl->uNumWindows] = hwnd; else return FALSE; //PrintWindowTitle(hwnd); lpwl->uNumWindows++; return TRUE; } WindowList GetWindowList(BOOL minimized) { WindowList wl = {0}; wl.list = (HWND*)malloc(1024*sizeof(HWND)); wl.uListLength = 1024; if(minimized) EnumWindows(EnumMinimizedWindowsProc, (LPARAM)(&wl)); else EnumWindows(EnumVisibleWindowsProc, (LPARAM)(&wl)); TRACE("Found %d windows\n", wl.uNumWindows); return wl; } // #################################################################################### // #################################################################################### // #################################################################################### // #################################################################################### // #################################################################################### // #################################################################################### // #################################################################################### void HandleUpKeyPress(WindowList* wl) { // TODO: minimize current window in the minimized list if(wl->uCurrent < wl->uNumWindows) { EnableWindowAlpha(wl->list[wl->uCurrent]); SetWindowAlpha(wl->list[wl->uCurrent], 45); wl->uCurrent++; } } void HandleLateralKeyPress(WindowList* wl, int left) { if(wl->uNumWindows > 0) { //ShowWindow(wl->list[wl->uCurrent], SW_HIDE); ShowWindow(wl->list[wl->uCurrent], SW_MINIMIZE); //ShowWindow(wl->list[wl->uCurrent], SW_SHOW); if(left) wl->uCurrent = (wl->uCurrent + wl->uNumWindows - 1)%wl->uNumWindows; else wl->uCurrent = (wl->uCurrent + 1)%wl->uNumWindows; //ShowWindow(wl->list[wl->uCurrent], SW_HIDE); ShowWindow(wl->list[wl->uCurrent], SW_RESTORE); //ShowWindow(wl->list[wl->uCurrent], SW_SHOW); BringWindowToTop(wl->list[wl->uCurrent]); } } LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { if((wParam == VK_LWIN || wParam == VK_RWIN)) TRACE("HOOK KEY\n"); if((wParam == VK_LWIN || wParam == VK_RWIN) && (lParam & 0x80000000)) { TRACE("HOOK UP\n"); SendMessage(g_hwndMain, WM_KEYUP, wParam, lParam); } return CallNextHookEx(g_hHookKeyboard, nCode, wParam, lParam); } LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static int hotkeydown = 0; static UINT CURRENT_LIST = 0; static WindowList wlVisible = {0}; static WindowList wlMinimized = {0}; switch(uMsg) { case WM_HOTKEY: if(wParam == ID_HOTKEY_UP) { if(wlVisible.list == NULL) wlVisible = GetWindowList(0); hotkeydown = 1; CURRENT_LIST = 0; HandleUpKeyPress(&wlVisible); SetFocus(hwnd); } if(wParam == ID_HOTKEY_RIGHT || wParam == ID_HOTKEY_LEFT) { if(wlMinimized.list == NULL) wlMinimized = GetWindowList(1); hotkeydown = 1; CURRENT_LIST = 1; HandleLateralKeyPress(&wlMinimized, wParam == ID_HOTKEY_LEFT); SetFocus(hwnd); } break; case WM_KEYDOWN: if(wParam == VK_DOWN && hotkeydown == 1 && wlVisible.uCurrent > 0) { CURRENT_LIST = 0; wlVisible.uCurrent--; DisableWindowAlpha(wlVisible.list[wlVisible.uCurrent]); } break; case WM_KEYUP: if(hotkeydown == 1 && (wParam == VK_LWIN || wParam == VK_RWIN)) { hotkeydown = 0; MultiDisableWindowAlpha(wlVisible); TRACE("Num Minimized: %d\n", wlMinimized.uNumWindows); if(CURRENT_LIST == 0) { if(wlMinimized.uNumWindows > 0) ShowWindow(wlMinimized.list[wlMinimized.uCurrent], SW_MINIMIZE); BringWindowToTop(wlVisible.list[wlVisible.uCurrent]); SetFocus(wlVisible.list[wlVisible.uCurrent]); } else if(wlMinimized.uNumWindows > 0) { TRACE("FINALLY\n"); PrintWindowTitle(wlMinimized.list[wlMinimized.uCurrent]); BringWindowToTop(wlMinimized.list[wlMinimized.uCurrent]); SetFocus(wlMinimized.list[wlMinimized.uCurrent]); } ClearWindowList(&wlVisible); ClearWindowList(&wlMinimized); } break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow) { MSG msg; HWND hwnd; WNDCLASSEX wcx = {0}; HMODULE hDLL = LoadLibrary("user32"); pSetLayeredWindowAttributes = (PSLWA)GetProcAddress(hDLL, "SetLayeredWindowAttributes"); InitCommonControls(); // enable visual styles wcx.cbSize = sizeof(wcx); wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wcx.hCursor = LoadCursor(NULL, IDC_ARROW); wcx.style = CS_HREDRAW | CS_VREDRAW; wcx.lpszClassName = "TaskSwitcherClass"; wcx.lpfnWndProc = MainWndProc; wcx.hInstance = hInstance; RegisterClassEx(&wcx); hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "TaskSwitcherClass", "Task Switcher", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, NULL, NULL, hInstance, NULL); g_hwndMain = hwnd; g_hHookKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hInstance, 0); RegisterHotKey(hwnd, ID_HOTKEY_UP, MOD_WIN, VK_UP); RegisterHotKey(hwnd, ID_HOTKEY_LEFT, MOD_WIN, VK_LEFT); RegisterHotKey(hwnd, ID_HOTKEY_RIGHT, MOD_WIN, VK_RIGHT); while(GetMessage(&msg, NULL, 0, 0)) { // TODO: process hotkey messages here, get rid of window TranslateMessage(&msg); DispatchMessage(&msg); } return 0; }