diff --git a/Src/StartMenu/StartMenuDLL/SettingsUI.cpp b/Src/StartMenu/StartMenuDLL/SettingsUI.cpp index d65df60ee..4524b0a3c 100644 --- a/Src/StartMenu/StartMenuDLL/SettingsUI.cpp +++ b/Src/StartMenu/StartMenuDLL/SettingsUI.cpp @@ -4482,6 +4482,9 @@ CSetting g_Settings[]={ {L"Tile",CSetting::TYPE_RADIO,IDS_TASK_TILE,IDS_TASK_TILE_TIP}, {L"Stretch",CSetting::TYPE_RADIO,IDS_TASK_STRETCH,IDS_TASK_STRETCH_TIP}, {L"TaskbarBordersV",CSetting::TYPE_STRING,IDS_TASK_BORDERS,IDS_TASK_BORDERS_TIP,L"0,0",CSetting::FLAG_CALLBACK,L"#TaskbarTileV=1",L"TaskbarTileV"}, + {L"PeekDesktopW11",CSetting::TYPE_BOOL,IDS_PEEKDESKTOPW11,IDS_PEEKDESKTOPW11_TIP,0}, + {L"PDW11_TaskbarSD",CSetting::TYPE_BOOL,IDS_PDW11_TASKBARSD,IDS_PDW11_TASKBARSD_TIP,1,0,L"PeekDesktopW11",L"PeekDesktopW11"}, + {L"PDW11_DelayTime",CSetting::TYPE_INT,IDS_PDW11_DELAY,IDS_PDW11_DELAY_TIP,450,0,L"PeekDesktopW11",L"PeekDesktopW11"}, {L"Metro",CSetting::TYPE_GROUP,IDS_METRO_SETTINGS}, {L"SkipMetro",CSetting::TYPE_BOOL,IDS_SKIP_METRO,IDS_SKIP_METRO_TIP,1,CSetting::FLAG_BASIC}, @@ -5115,6 +5118,12 @@ void UpdateSettings( void ) pSetting->flags |= CSetting::FLAG_HIDDEN; pSetting->value = 0; HideSetting(L"UseTaskbarAl", true); + + pSetting = FindSetting(L"PeekDesktopW11"); + pSetting->flags |= CSetting::FLAG_HIDDEN; + pSetting->value = 0; + HideSetting(L"PDW11_TaskbarSD", true); + HideSetting(L"PDW11_DelayTime", true); } } diff --git a/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp b/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp index e6d3f05a1..c2375a777 100644 --- a/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp +++ b/Src/StartMenu/StartMenuDLL/StartMenuDLL.cpp @@ -37,7 +37,7 @@ typedef std::map id_taskbar_map; id_taskbar_map g_TaskbarInfos; static int g_LastTaskbar=MAIN_TASK_BAR; static int g_NextTaskbar=0; -HWND g_TaskBar, g_OwnerWindow; +HWND g_TaskBar, g_OwnerWindow, g_TrayWnd; HWND g_TopWin7Menu, g_AllPrograms, g_ProgramsButton, g_UserPic; // from the Windows menu HWND g_ProgWin; HMONITOR g_WSMHMonitor; @@ -473,6 +473,8 @@ STARTMENUAPI HWND FindTaskBar( DWORD process ) } g_OwnerWindow=g_Owner.Create(NULL,0,0,WS_POPUP,WS_EX_TOOLWINDOW|WS_EX_TOPMOST); } + if (!g_TrayWnd) + g_TrayWnd = FindWindowEx(g_TaskBar, NULL, L"TrayNotifyWnd", NULL); } return g_TaskBar; } @@ -3515,9 +3517,57 @@ static LRESULT CALLBACK HookProgManThread( int code, WPARAM wParam, LPARAM lPara return CallNextHookEx(NULL,code,wParam,lParam); } +static BOOL PDW11_WinDown = FALSE; +static HHOOK PDW11_hk = NULL; + +LPRECT PDW11_GetPeekBox(LPRECT rcTray) { + GetWindowRect(g_TrayWnd, rcTray); + rcTray->left = rcTray->right - ScaleForDpi(g_TrayWnd, 12); + rcTray->right += 1, rcTray->bottom += 1; + return rcTray; +} + +UINT PDW11_RWinUp( void ) { + INPUT input = {}; + input.type = INPUT_KEYBOARD; + input.ki.wVk = VK_RWIN; + input.ki.dwFlags = KEYEVENTF_KEYUP; + return SendInput(1, &input, sizeof(INPUT)); +} + +static LRESULT CALLBACK PeekDeskW11MouseProcLL(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (PDW11_WinDown && nCode == HC_ACTION && wParam == WM_MOUSEMOVE) { + auto info = (LPMSLLHOOKSTRUCT)lParam; + RECT rcBox; + if (!PtInRect(PDW11_GetPeekBox(&rcBox), info->pt)) { + PDW11_RWinUp(); + PDW11_WinDown = FALSE; + + if (PDW11_hk) { + UnhookWindowsHookEx(PDW11_hk); PDW11_hk = NULL; + } + } + } + return CallNextHookEx(0, nCode, wParam, lParam); +} + +static bool GetWin11TaskbarSD(void) +{ + CRegKey regKey; + if (regKey.Open(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced)", KEY_READ) == ERROR_SUCCESS) + { + DWORD val; + return regKey.QueryDWORDValue(L"TaskbarSD", val) == ERROR_SUCCESS ? val : true; // peek button enabled by default + } + return true; +} + // WH_MOUSE hook for taskbar thread (Win11+) static LRESULT CALLBACK HookDesktopThreadMouse(int code, WPARAM wParam, LPARAM lParam) { + static DWORD PDW11_HoverStart = 0; + if (code == HC_ACTION) { // we need to steal mouse messages that are issues in start button area @@ -3528,6 +3578,51 @@ static LRESULT CALLBACK HookDesktopThreadMouse(int code, WPARAM wParam, LPARAM l if (!taskBar) { taskBar = FindTaskBarInfoBar(GetAncestor(info->hwnd, GA_ROOT)); // click on taskbar + + // Peek Desktop for Windows 11 feature + if (GetSettingBool(L"PeekDesktopW11") && !PDW11_WinDown && taskBar && g_TrayWnd && wParam == WM_MOUSEMOVE) { + RECT rcBox; + if (PtInRect(PDW11_GetPeekBox(&rcBox), info->pt)) { + + // Optimization: check for registry only if mouse in PeekBox + // if system taskbar peek button is off and PDW11_TaskbarSD not set, peek desktop anyway + if (!GetSettingBool(L"PDW11_TaskbarSD") || GetWin11TaskbarSD()) { + if (!PDW11_HoverStart) + PDW11_HoverStart = GetTickCount(); + int delay = GetSettingInt(L"PDW11_DelayTime"); + // Delay here is not so precise because system send mouse messages in fixed delay + // I haven't been able to get this to work consistently through timer, therefore lets rely on fact + // that system continue sending WM_MOUSEMOVE even if cursor is not moving and just hovered over taskbar window + if (GetTickCount() - PDW11_HoverStart >= (delay < 100 ? 100 : delay)) { // 100ms is minimum stable delay in my tests + INPUT inputs[3] = {}; + + inputs[0].type = INPUT_KEYBOARD; + inputs[0].ki.wVk = VK_RWIN; + + inputs[1].type = INPUT_KEYBOARD; + inputs[1].ki.wVk = VK_OEM_COMMA; + + inputs[2].type = INPUT_KEYBOARD; + inputs[2].ki.wVk = VK_OEM_COMMA; + inputs[2].ki.dwFlags = KEYEVENTF_KEYUP; + + UINT uSent = SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT)); + + PDW11_WinDown = TRUE; + PDW11_HoverStart = 0; + if (!PDW11_hk) + PDW11_hk = SetWindowsHookEx(WH_MOUSE_LL, PeekDeskW11MouseProcLL, g_Instance, NULL); + // Release Win key immediately if mouse hook can not be installed for some reasons + if (!PDW11_hk) { + PDW11_RWinUp(); PDW11_WinDown = FALSE; + } + } + } + } + else + PDW11_HoverStart = 0; + } + if (taskBar && !PointAroundStartButton(taskBar->taskbarId)) taskBar = NULL; } diff --git a/Src/StartMenu/StartMenuDLL/StartMenuDLL.rc b/Src/StartMenu/StartMenuDLL/StartMenuDLL.rc index 8afd1734f..9149b147f 100644 --- a/Src/StartMenu/StartMenuDLL/StartMenuDLL.rc +++ b/Src/StartMenu/StartMenuDLL/StartMenuDLL.rc @@ -653,7 +653,7 @@ BEGIN IDS_ALIGN_WORK_AREA "Align start menu to working area" IDS_ALIGN_WORK_AREA_TIP "Align the start menu to the working area instead of to the taskbar. Use with custom taskbars" IDS_ALIGN_CENTER "Align start menu to screen center" - IDS_ALIGN_CENTER_TIP "Align the start menu to center width of screen. This setting is usefull on Windows 11 with center taskbar alignment" + IDS_ALIGN_CENTER_TIP "Align the start menu to center width of screen. This setting is useful on Windows 11 with center taskbar alignment" IDS_ALIGN_TASKBAR "Follow system taskbar alignment" IDS_ALIGN_TASKBAR_TIP "Start menu will only be centered if system taskbar uses center alignment" IDS_HOR_OFFSET "Horizontal position offset" @@ -1295,6 +1295,12 @@ BEGIN IDS_TASK_STRETCHH_TIP "Choose how to stretch the texture horizontally" IDS_TASK_STRETCHV "Vertical stretching" IDS_TASK_STRETCHV_TIP "Choose how to stretch the texture vertically" + IDS_PEEKDESKTOPW11 "Peek Desktop (Windows 11)" + IDS_PEEKDESKTOPW11_TIP "Brings back the classic peek desktop feature when hovering mouse over the right edge of system tray." + IDS_PDW11_TASKBARSD "Follow system taskbar behavior" + IDS_PDW11_TASKBARSD_TIP "Peek desktop feature will only work if ""Select the far corner of the taskbar to show desktop"" option set in Settings - Personalization - Taskbar - Taskbar behavior." + IDS_PDW11_DELAY "Hover delay" + IDS_PDW11_DELAY_TIP "Enter delay (in ms) for hovering over tray edge to peek desktop (minimum 100ms)" END STRINGTABLE diff --git a/Src/StartMenu/StartMenuDLL/resource.h b/Src/StartMenu/StartMenuDLL/resource.h index db016a483..3b6b7a30a 100644 --- a/Src/StartMenu/StartMenuDLL/resource.h +++ b/Src/StartMenu/StartMenuDLL/resource.h @@ -790,6 +790,12 @@ #define IDS_ALIGN_CENTER_TIP 3691 #define IDS_ALIGN_TASKBAR 3692 #define IDS_ALIGN_TASKBAR_TIP 3693 +#define IDS_PEEKDESKTOPW11 3694 +#define IDS_PEEKDESKTOPW11_TIP 3695 +#define IDS_PDW11_DELAY 3696 +#define IDS_PDW11_DELAY_TIP 3697 +#define IDS_PDW11_TASKBARSD 3698 +#define IDS_PDW11_TASKBARSD_TIP 3699 #define IDS_STRING7001 7001 #define IDS_STRING7002 7002 #define IDS_STRING7003 7003