From 89330986f499df4c8832cce76e8c6c594f1bca39 Mon Sep 17 00:00:00 2001 From: Okami Wong Date: Fri, 18 Nov 2022 22:22:40 +0800 Subject: [PATCH] [Shortcut Guide] Support delayed display of shortcuts except for taskbar shortcuts (#21762) * Implement the delayed rendering * Impelement settings UI * Rename * Set the minimum of ShortcutGuide_PressTimeForTaskbarIconShortcuts to 100ms * Separate the animations of the global windows shortcuts and the taskbar icon shortcuts * Amend * Handle the case when the shortcut guide is not activated by win key long press * Remove .vscode * Keep the user's original setting of the win key press time * Revert the default press time to 900 ms * Restore default as 900 --- .../ShortcutGuide/ShortcutGuideSettings.h | 3 +- .../ShortcutGuide/overlay_window.cpp | 535 ++++++++++-------- .../ShortcutGuide/overlay_window.h | 10 +- .../ShortcutGuide/shortcut_guide.cpp | 53 +- .../ShortcutGuide/shortcut_guide.h | 11 +- .../ShortcutGuide/ShortcutGuide/trace.cpp | 3 +- .../ShortcutGuideModuleInterface/dllmain.cpp | 17 +- .../ShortcutGuideProperties.cs | 8 +- .../Settings.UI/Strings/en-us/Resources.resw | 11 +- .../ViewModels/ShortcutGuideViewModel.cs | 32 +- .../Settings.UI/Views/ShortcutGuidePage.xaml | 16 +- 11 files changed, 424 insertions(+), 275 deletions(-) diff --git a/src/modules/ShortcutGuide/ShortcutGuide/ShortcutGuideSettings.h b/src/modules/ShortcutGuide/ShortcutGuide/ShortcutGuideSettings.h index 0f6b131f25..a39f2f2511 100644 --- a/src/modules/ShortcutGuide/ShortcutGuide/ShortcutGuideSettings.h +++ b/src/modules/ShortcutGuide/ShortcutGuide/ShortcutGuideSettings.h @@ -8,5 +8,6 @@ struct ShortcutGuideSettings std::wstring theme = L"system"; std::wstring disabledApps = L""; bool shouldReactToPressedWinKey = false; - int windowsKeyPressTime = 900; + int windowsKeyPressTimeForGlobalWindowsShortcuts = 900; + int windowsKeyPressTimeForTaskbarIconShortcuts = 900; }; diff --git a/src/modules/ShortcutGuide/ShortcutGuide/overlay_window.cpp b/src/modules/ShortcutGuide/ShortcutGuide/overlay_window.cpp index e3d2a578b5..9436b9f463 100644 --- a/src/modules/ShortcutGuide/ShortcutGuide/overlay_window.cpp +++ b/src/modules/ShortcutGuide/ShortcutGuide/overlay_window.cpp @@ -268,7 +268,11 @@ D2D1_RECT_F D2DOverlaySVG::get_snap_right() const } D2DOverlayWindow::D2DOverlayWindow() : - total_screen({}), animation(0.3), D2DWindow() + total_screen({}), + background_animation(0.3), + global_windows_shortcuts_animation(0.3), + taskbar_icon_shortcuts_animation(0.3), + D2DWindow() { tasklist_thread = std::thread([&] { while (running) @@ -356,7 +360,29 @@ void D2DOverlayWindow::show(HWND active_window, bool snappable) // Ignore errors, if this fails we will just not show the thumbnail DwmRegisterThumbnail(hwnd, active_window, &thumbnail); } - animation.reset(); + + background_animation.reset(); + + if (milliseconds_press_time_for_global_windows_shortcuts < milliseconds_press_time_for_taskbar_icon_shortcuts) + { + global_windows_shortcuts_shown = true; + taskbar_icon_shortcuts_shown = false; + global_windows_shortcuts_animation.reset(); + } + else if (milliseconds_press_time_for_global_windows_shortcuts > milliseconds_press_time_for_taskbar_icon_shortcuts) + { + global_windows_shortcuts_shown = false; + taskbar_icon_shortcuts_shown = true; + taskbar_icon_shortcuts_animation.reset(); + } + else + { + global_windows_shortcuts_shown = true; + taskbar_icon_shortcuts_shown = true; + global_windows_shortcuts_animation.reset(); + taskbar_icon_shortcuts_animation.reset(); + } + auto primary_size = MonitorInfo::GetPrimaryMonitor().GetScreenSize(false); shown_start_time = std::chrono::steady_clock::now(); lock.unlock(); @@ -422,6 +448,16 @@ void D2DOverlayWindow::apply_overlay_opacity(float opacity) overlay_opacity = opacity; } +void D2DOverlayWindow::apply_press_time_for_global_windows_shortcuts(int press_time) +{ + milliseconds_press_time_for_global_windows_shortcuts = std::max(press_time, 0); +} + +void D2DOverlayWindow::apply_press_time_for_taskbar_icon_shortcuts(int press_time) +{ + milliseconds_press_time_for_taskbar_icon_shortcuts = std::max(press_time, 0); +} + void D2DOverlayWindow::set_theme(const std::wstring& theme) { if (theme == L"light") @@ -524,7 +560,7 @@ void D2DOverlayWindow::resize() text.resize(font, use_overlay->get_scale()); } -void render_arrow(D2DSVG& arrow, TasklistButton& button, RECT window, float max_scale, ID2D1DeviceContext5* d2d_dc) +void render_arrow(D2DSVG& arrow, TasklistButton& button, RECT window, float max_scale, ID2D1DeviceContext5* d2d_dc, int x_offset, int y_offset) { int dx = 0, dy = 0; // Calculate taskbar orientation @@ -558,8 +594,8 @@ void render_arrow(D2DSVG& arrow, TasklistButton& button, RECT window, float max_ // assume button is 25% wider than taller, +10% to make room for each of the arrows that are hidden auto render_arrow_width = (int)(button.height * 1.25f * 1.2f); auto render_arrow_height = (int)(render_arrow_width * arrow_ratio); - arrow.resize(button.x + (button.width - render_arrow_width) / 2, - dy == -1 ? button.y - render_arrow_height : 0, + arrow.resize((button.x + (button.width - render_arrow_width) / 2) + x_offset, + (dy == -1 ? button.y - render_arrow_height : 0) + y_offset, render_arrow_width, render_arrow_height, 0.95f, @@ -571,8 +607,8 @@ void render_arrow(D2DSVG& arrow, TasklistButton& button, RECT window, float max_ // same as above - make room for the hidden arrow auto render_arrow_height = (int)(button.height * 1.2f); auto render_arrow_width = (int)(render_arrow_height / arrow_ratio); - arrow.resize(dx == -1 ? button.x - render_arrow_width : 0, - button.y + (button.height - render_arrow_height) / 2, + arrow.resize((dx == -1 ? button.x - render_arrow_width : 0) + x_offset, + (button.y + (button.height - render_arrow_height) / 2) + y_offset, render_arrow_width, render_arrow_height, 0.95f, @@ -617,35 +653,15 @@ void D2DOverlayWindow::render(ID2D1DeviceContext5* d2d_dc) } d2d_dc->Clear(); - int x_offset = 0, y_offset = 0; - auto current_anim_value = (float)animation.value(Animation::AnimFunctions::LINEAR); - SetLayeredWindowAttributes(hwnd, 0, static_cast(255 * current_anim_value), LWA_ALPHA); - double pos_anim_value = 1 - animation.value(Animation::AnimFunctions::EASE_OUT_EXPO); - if (!tasklist_buttons.empty()) - { - if (tasklist_buttons[0].x <= window_rect.left) - { // taskbar on left - x_offset = (int)(-pos_anim_value * use_overlay->width() * use_overlay->get_scale()); - } - if (tasklist_buttons[0].x >= window_rect.right) - { // taskbar on right - x_offset = (int)(pos_anim_value * use_overlay->width() * use_overlay->get_scale()); - } - if (tasklist_buttons[0].y <= window_rect.top) - { // taskbar on top - y_offset = (int)(-pos_anim_value * use_overlay->height() * use_overlay->get_scale()); - } - if (tasklist_buttons[0].y >= window_rect.bottom) - { // taskbar on bottom - y_offset = (int)(pos_anim_value * use_overlay->height() * use_overlay->get_scale()); - } - } - else - { - x_offset = 0; - y_offset = (int)(pos_anim_value * use_overlay->height() * use_overlay->get_scale()); - } + int taskbar_icon_shortcuts_x_offset = 0, taskbar_icon_shortcuts_y_offset = 0; + + float current_background_anim_value = (float)background_animation.value(Animation::AnimFunctions::LINEAR); + float current_global_windows_shortcuts_anim_value = (float)global_windows_shortcuts_animation.value(Animation::AnimFunctions::LINEAR); + float pos_global_windows_shortcuts_anim_value = 1 - (float)global_windows_shortcuts_animation.value(Animation::AnimFunctions::EASE_OUT_EXPO); + float pos_taskbar_icon_shortcuts_anim_value = 1 - (float)taskbar_icon_shortcuts_animation.value(Animation::AnimFunctions::EASE_OUT_EXPO); + // Draw background + SetLayeredWindowAttributes(hwnd, 0, static_cast(255 * current_background_anim_value), LWA_ALPHA); winrt::com_ptr brush; float brush_opacity = get_overlay_opacity(); D2D1_COLOR_F brushColor = light_mode ? D2D1::ColorF(1.0f, 1.0f, 1.0f, brush_opacity) : D2D1::ColorF(0, 0, 0, brush_opacity); @@ -656,225 +672,274 @@ void D2DOverlayWindow::render(ID2D1DeviceContext5* d2d_dc) d2d_dc->SetTransform(D2D1::Matrix3x2F::Identity()); d2d_dc->FillRectangle(background_rect, brush.get()); - // Thumbnail logic: - auto window_state = get_window_state(active_window); - auto thumb_window = get_window_pos(active_window); - if (!thumb_window.has_value()) + // Draw the taskbar shortcuts (the arrows with numbers) + if (taskbar_icon_shortcuts_shown) { - thumb_window = RECT(); - } - - bool miniature_shown = active_window != nullptr && thumbnail != nullptr && thumb_window && window_state != MINIMIZED; - RECT client_rect; - if (thumb_window && GetClientRect(active_window, &client_rect)) - { - int dx = ((thumb_window->right - thumb_window->left) - (client_rect.right - client_rect.left)) / 2; - int dy = ((thumb_window->bottom - thumb_window->top) - (client_rect.bottom - client_rect.top)) / 2; - thumb_window->left += dx; - thumb_window->right -= dx; - thumb_window->top += dy; - thumb_window->bottom -= dy; - } - if (miniature_shown && thumb_window->right - thumb_window->left <= 0 || thumb_window->bottom - thumb_window->top <= 0) - { - miniature_shown = false; - } - bool render_monitors = true; - auto total_monitor_with_screen = total_screen; - if (thumb_window) - { - total_monitor_with_screen.rect.left = std::min(total_monitor_with_screen.rect.left, thumb_window->left + monitor_dx); - total_monitor_with_screen.rect.top = std::min(total_monitor_with_screen.rect.top, thumb_window->top + monitor_dy); - total_monitor_with_screen.rect.right = std::max(total_monitor_with_screen.rect.right, thumb_window->right + monitor_dx); - total_monitor_with_screen.rect.bottom = std::max(total_monitor_with_screen.rect.bottom, thumb_window->bottom + monitor_dy); - } - // Only allow the new rect being slight bigger. - if (total_monitor_with_screen.width() - total_screen.width() > (thumb_window->right - thumb_window->left) / 2 || - total_monitor_with_screen.height() - total_screen.height() > (thumb_window->bottom - thumb_window->top) / 2) - { - render_monitors = false; - } - if (window_state == MINIMIZED) - { - total_monitor_with_screen = total_screen; - } - auto rect_and_scale = use_overlay->get_thumbnail_rect_and_scale(0, 0, total_monitor_with_screen.width(), total_monitor_with_screen.height(), 1); - if (miniature_shown) - { - RECT thumbnail_pos; - if (render_monitors) + if (!tasklist_buttons.empty()) { - thumbnail_pos.left = (int)((thumb_window->left + monitor_dx) * rect_and_scale.scale + rect_and_scale.rect.left); - thumbnail_pos.top = (int)((thumb_window->top + monitor_dy) * rect_and_scale.scale + rect_and_scale.rect.top); - thumbnail_pos.right = (int)((thumb_window->right + monitor_dx) * rect_and_scale.scale + rect_and_scale.rect.left); - thumbnail_pos.bottom = (int)((thumb_window->bottom + monitor_dy) * rect_and_scale.scale + rect_and_scale.rect.top); + if (tasklist_buttons[0].x <= window_rect.left) + { + // taskbar on left + taskbar_icon_shortcuts_x_offset = (int)(-pos_taskbar_icon_shortcuts_anim_value * use_overlay->width() * use_overlay->get_scale()); + } + if (tasklist_buttons[0].x >= window_rect.right) + { + // taskbar on right + taskbar_icon_shortcuts_x_offset = (int)(pos_taskbar_icon_shortcuts_anim_value * use_overlay->width() * use_overlay->get_scale()); + } + if (tasklist_buttons[0].y <= window_rect.top) + { + // taskbar on top + taskbar_icon_shortcuts_y_offset = (int)(-pos_taskbar_icon_shortcuts_anim_value * use_overlay->height() * use_overlay->get_scale()); + } + if (tasklist_buttons[0].y >= window_rect.bottom) + { + // taskbar on bottom + taskbar_icon_shortcuts_y_offset = (int)(pos_taskbar_icon_shortcuts_anim_value * use_overlay->height() * use_overlay->get_scale()); + } + for (auto&& button : tasklist_buttons) + { + if ((size_t)(button.keynum) - 1 >= arrows.size()) + { + continue; + } + render_arrow(arrows[(size_t)(button.keynum) - 1], button, window_rect, use_overlay->get_scale(), d2d_dc, taskbar_icon_shortcuts_x_offset, taskbar_icon_shortcuts_y_offset); + } } - else - { - thumbnail_pos = use_overlay->get_thumbnail_rect_and_scale(0, 0, thumb_window->right - thumb_window->left, thumb_window->bottom - thumb_window->top, 1).rect; - } - // If the animation is done show the thumbnail - // we cannot animate the thumbnail, the animation lags behind - miniature_shown = show_thumbnail(thumbnail_pos, current_anim_value); } else { - hide_thumbnail(); - } - if (window_state == MINIMIZED) - { - render_monitors = true; - } - // render the monitors - if (render_monitors) - { - brushColor = D2D1::ColorF(colors.start_color_menu, miniature_shown ? current_anim_value * 0.9f : current_anim_value * 0.3f); - brush = nullptr; - winrt::check_hresult(d2d_dc->CreateSolidColorBrush(brushColor, brush.put())); - for (auto& monitor : monitors) + auto time_since_start = std::chrono::high_resolution_clock::now() - shown_start_time; + if (time_since_start.count() / 1000000 > milliseconds_press_time_for_taskbar_icon_shortcuts - milliseconds_press_time_for_global_windows_shortcuts) { - D2D1_RECT_F monitor_rect; - const auto monitor_size = monitor.GetScreenSize(true); - monitor_rect.left = (float)((monitor_size.left() + monitor_dx) * rect_and_scale.scale + rect_and_scale.rect.left); - monitor_rect.top = (float)((monitor_size.top() + monitor_dy) * rect_and_scale.scale + rect_and_scale.rect.top); - monitor_rect.right = (float)((monitor_size.right() + monitor_dx) * rect_and_scale.scale + rect_and_scale.rect.left); - monitor_rect.bottom = (float)((monitor_size.bottom() + monitor_dy) * rect_and_scale.scale + rect_and_scale.rect.top); - d2d_dc->SetTransform(D2D1::Matrix3x2F::Identity()); - d2d_dc->FillRectangle(monitor_rect, brush.get()); + taskbar_icon_shortcuts_shown = true; + taskbar_icon_shortcuts_animation.reset(); } } - // Finalize the overlay - dimm the buttons if no thumbnail is present and show "No active window" - use_overlay->toggle_window_group(miniature_shown || window_state == MINIMIZED); - if (!miniature_shown && window_state != MINIMIZED) - { - no_active.render(d2d_dc); - window_state = UNKNOWN; - } - // Set the animation - move the draw window according to animation step - auto popIn = D2D1::Matrix3x2F::Translation((float)x_offset, (float)y_offset); - d2d_dc->SetTransform(popIn); - - // Animate keys - for (unsigned id = 0; id < key_animations.size();) + if (global_windows_shortcuts_shown) { - auto& animation = key_animations[id]; - D2D1_COLOR_F color; - auto value = (float)animation.animation.value(Animation::AnimFunctions::EASE_OUT_EXPO); - color.a = 1.0f; - color.r = animation.original.r + (1.0f - animation.original.r) * value; - color.g = animation.original.g + (1.0f - animation.original.g) * value; - color.b = animation.original.b + (1.0f - animation.original.b) * value; - animation.button->SetAttributeValue(L"fill", color); - if (animation.animation.done()) + // Thumbnail logic: + auto window_state = get_window_state(active_window); + auto thumb_window = get_window_pos(active_window); + if (!thumb_window.has_value()) { - if (value == 1) + thumb_window = RECT(); + } + + bool miniature_shown = active_window != nullptr && thumbnail != nullptr && thumb_window && window_state != MINIMIZED; + RECT client_rect; + if (thumb_window && GetClientRect(active_window, &client_rect)) + { + int dx = ((thumb_window->right - thumb_window->left) - (client_rect.right - client_rect.left)) / 2; + int dy = ((thumb_window->bottom - thumb_window->top) - (client_rect.bottom - client_rect.top)) / 2; + thumb_window->left += dx; + thumb_window->right -= dx; + thumb_window->top += dy; + thumb_window->bottom -= dy; + } + if (miniature_shown && thumb_window->right - thumb_window->left <= 0 || thumb_window->bottom - thumb_window->top <= 0) + { + miniature_shown = false; + } + bool render_monitors = true; + auto total_monitor_with_screen = total_screen; + if (thumb_window) + { + total_monitor_with_screen.rect.left = std::min(total_monitor_with_screen.rect.left, thumb_window->left + monitor_dx); + total_monitor_with_screen.rect.top = std::min(total_monitor_with_screen.rect.top, thumb_window->top + monitor_dy); + total_monitor_with_screen.rect.right = std::max(total_monitor_with_screen.rect.right, thumb_window->right + monitor_dx); + total_monitor_with_screen.rect.bottom = std::max(total_monitor_with_screen.rect.bottom, thumb_window->bottom + monitor_dy); + } + // Only allow the new rect being slight bigger. + if (total_monitor_with_screen.width() - total_screen.width() > (thumb_window->right - thumb_window->left) / 2 || + total_monitor_with_screen.height() - total_screen.height() > (thumb_window->bottom - thumb_window->top) / 2) + { + render_monitors = false; + } + if (window_state == MINIMIZED) + { + total_monitor_with_screen = total_screen; + } + auto rect_and_scale = use_overlay->get_thumbnail_rect_and_scale(0, 0, total_monitor_with_screen.width(), total_monitor_with_screen.height(), 1); + if (miniature_shown) + { + RECT thumbnail_pos; + if (render_monitors) { - animation.animation.reset(0.05, 1, 0); - animation.animation.value(Animation::AnimFunctions::EASE_OUT_EXPO); + thumbnail_pos.left = (int)((thumb_window->left + monitor_dx) * rect_and_scale.scale + rect_and_scale.rect.left); + thumbnail_pos.top = (int)((thumb_window->top + monitor_dy) * rect_and_scale.scale + rect_and_scale.rect.top); + thumbnail_pos.right = (int)((thumb_window->right + monitor_dx) * rect_and_scale.scale + rect_and_scale.rect.left); + thumbnail_pos.bottom = (int)((thumb_window->bottom + monitor_dy) * rect_and_scale.scale + rect_and_scale.rect.top); } else { - key_animations.erase(key_animations.begin() + id); - continue; + thumbnail_pos = use_overlay->get_thumbnail_rect_and_scale(0, 0, thumb_window->right - thumb_window->left, thumb_window->bottom - thumb_window->top, 1).rect; + } + // If the animation is done show the thumbnail + // we cannot animate the thumbnail, the animation lags behind + miniature_shown = show_thumbnail(thumbnail_pos, current_global_windows_shortcuts_anim_value); + } + else + { + hide_thumbnail(); + } + if (window_state == MINIMIZED) + { + render_monitors = true; + } + // render the monitors + if (render_monitors) + { + brushColor = D2D1::ColorF(colors.start_color_menu, miniature_shown ? current_global_windows_shortcuts_anim_value * 0.9f : current_global_windows_shortcuts_anim_value * 0.3f); + brush = nullptr; + winrt::check_hresult(d2d_dc->CreateSolidColorBrush(brushColor, brush.put())); + for (auto& monitor : monitors) + { + D2D1_RECT_F monitor_rect; + const auto monitor_size = monitor.GetScreenSize(true); + monitor_rect.left = (float)((monitor_size.left() + monitor_dx) * rect_and_scale.scale + rect_and_scale.rect.left); + monitor_rect.top = (float)((monitor_size.top() + monitor_dy) * rect_and_scale.scale + rect_and_scale.rect.top); + monitor_rect.right = (float)((monitor_size.right() + monitor_dx) * rect_and_scale.scale + rect_and_scale.rect.left); + monitor_rect.bottom = (float)((monitor_size.bottom() + monitor_dy) * rect_and_scale.scale + rect_and_scale.rect.top); + d2d_dc->SetTransform(D2D1::Matrix3x2F::Identity()); + d2d_dc->FillRectangle(monitor_rect, brush.get()); } } - ++id; - } - // Finally: render the overlay... - use_overlay->render(d2d_dc); - // ... window arrows texts ... - std::wstring left, right, up, down; - bool left_disabled = false; - bool right_disabled = false; - bool up_disabled = false; - bool down_disabled = false; - switch (window_state) - { - case MINIMIZED: - left = GET_RESOURCE_STRING(IDS_NO_ACTION); - left_disabled = true; - right = GET_RESOURCE_STRING(IDS_NO_ACTION); - right_disabled = true; - up = GET_RESOURCE_STRING(IDS_RESTORE); - down = GET_RESOURCE_STRING(IDS_NO_ACTION); - down_disabled = true; - break; - case MAXIMIZED: - left = GET_RESOURCE_STRING(IDS_SNAP_LEFT); - right = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); - up = GET_RESOURCE_STRING(IDS_NO_ACTION); - up_disabled = true; - down = GET_RESOURCE_STRING(IDS_RESTORE); - break; - case SNAPPED_TOP_LEFT: - left = GET_RESOURCE_STRING(IDS_SNAP_UPPER_RIGHT); - right = GET_RESOURCE_STRING(IDS_SNAP_UPPER_RIGHT); - up = GET_RESOURCE_STRING(IDS_MAXIMIZE); - down = GET_RESOURCE_STRING(IDS_SNAP_LEFT); - break; - case SNAPPED_LEFT: - left = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); - right = GET_RESOURCE_STRING(IDS_RESTORE); - up = GET_RESOURCE_STRING(IDS_SNAP_UPPER_LEFT); - down = GET_RESOURCE_STRING(IDS_SNAP_LOWER_LEFT); - break; - case SNAPPED_BOTTOM_LEFT: - left = GET_RESOURCE_STRING(IDS_SNAP_LOWER_RIGHT); - right = GET_RESOURCE_STRING(IDS_SNAP_LOWER_RIGHT); - up = GET_RESOURCE_STRING(IDS_SNAP_LEFT); - down = GET_RESOURCE_STRING(IDS_MINIMIZE); - break; - case SNAPPED_TOP_RIGHT: - left = GET_RESOURCE_STRING(IDS_SNAP_UPPER_LEFT); - right = GET_RESOURCE_STRING(IDS_SNAP_UPPER_LEFT); - up = GET_RESOURCE_STRING(IDS_MAXIMIZE); - down = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); - break; - case SNAPPED_RIGHT: - left = GET_RESOURCE_STRING(IDS_RESTORE); - right = GET_RESOURCE_STRING(IDS_SNAP_LEFT); - up = GET_RESOURCE_STRING(IDS_SNAP_UPPER_RIGHT); - down = GET_RESOURCE_STRING(IDS_SNAP_LOWER_RIGHT); - break; - case SNAPPED_BOTTOM_RIGHT: - left = GET_RESOURCE_STRING(IDS_SNAP_LOWER_LEFT); - right = GET_RESOURCE_STRING(IDS_SNAP_LOWER_LEFT); - up = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); - down = GET_RESOURCE_STRING(IDS_MINIMIZE); - break; - case RESTORED: - left = GET_RESOURCE_STRING(IDS_SNAP_LEFT); - right = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); - up = GET_RESOURCE_STRING(IDS_MAXIMIZE); - down = GET_RESOURCE_STRING(IDS_MINIMIZE); - break; - default: - left = GET_RESOURCE_STRING(IDS_NO_ACTION); - left_disabled = true; - right = GET_RESOURCE_STRING(IDS_NO_ACTION); - right_disabled = true; - up = GET_RESOURCE_STRING(IDS_NO_ACTION); - up_disabled = true; - down = GET_RESOURCE_STRING(IDS_NO_ACTION); - down_disabled = true; - } - auto text_color = D2D1::ColorF(light_mode ? 0x222222 : 0xDDDDDD, active_window_snappable && (miniature_shown || window_state == MINIMIZED) ? 1.0f : 0.3f); - use_overlay->find_element(L"KeyUpGroup")->SetAttributeValue(L"fill-opacity", up_disabled ? 0.3f : 1.0f); - text.set_alignment_center().write(d2d_dc, text_color, use_overlay->get_maximize_label(), up); - use_overlay->find_element(L"KeyDownGroup")->SetAttributeValue(L"fill-opacity", down_disabled ? 0.3f : 1.0f); - text.write(d2d_dc, text_color, use_overlay->get_minimize_label(), down); - use_overlay->find_element(L"KeyLeftGroup")->SetAttributeValue(L"fill-opacity", left_disabled ? 0.3f : 1.0f); - text.set_alignment_right().write(d2d_dc, text_color, use_overlay->get_snap_left(), left); - use_overlay->find_element(L"KeyRightGroup")->SetAttributeValue(L"fill-opacity", right_disabled ? 0.3f : 1.0f); - text.set_alignment_left().write(d2d_dc, text_color, use_overlay->get_snap_right(), right); - // ... and the arrows with numbers - for (auto&& button : tasklist_buttons) - { - if ((size_t)(button.keynum) - 1 >= arrows.size()) + // Finalize the overlay - dimm the buttons if no thumbnail is present and show "No active window" + use_overlay->toggle_window_group(miniature_shown || window_state == MINIMIZED); + if (!miniature_shown && window_state != MINIMIZED) { - continue; + no_active.render(d2d_dc); + window_state = UNKNOWN; + } + + // Set the animation - move the draw window according to animation step + int global_windows_shortcuts_y_offset = (int)(pos_global_windows_shortcuts_anim_value * use_overlay->height() * use_overlay->get_scale()); + auto popIn = D2D1::Matrix3x2F::Translation(0, (float)global_windows_shortcuts_y_offset); + d2d_dc->SetTransform(popIn); + + // Animate keys + for (unsigned id = 0; id < key_animations.size();) + { + auto& animation = key_animations[id]; + D2D1_COLOR_F color; + auto value = (float)animation.animation.value(Animation::AnimFunctions::EASE_OUT_EXPO); + color.a = 1.0f; + color.r = animation.original.r + (1.0f - animation.original.r) * value; + color.g = animation.original.g + (1.0f - animation.original.g) * value; + color.b = animation.original.b + (1.0f - animation.original.b) * value; + animation.button->SetAttributeValue(L"fill", color); + if (animation.animation.done()) + { + if (value == 1) + { + animation.animation.reset(0.05, 1, 0); + animation.animation.value(Animation::AnimFunctions::EASE_OUT_EXPO); + } + else + { + key_animations.erase(key_animations.begin() + id); + continue; + } + } + ++id; + } + // Finally: render the overlay... + use_overlay->render(d2d_dc); + // ... window arrows texts ... + std::wstring left, right, up, down; + bool left_disabled = false; + bool right_disabled = false; + bool up_disabled = false; + bool down_disabled = false; + switch (window_state) + { + case MINIMIZED: + left = GET_RESOURCE_STRING(IDS_NO_ACTION); + left_disabled = true; + right = GET_RESOURCE_STRING(IDS_NO_ACTION); + right_disabled = true; + up = GET_RESOURCE_STRING(IDS_RESTORE); + down = GET_RESOURCE_STRING(IDS_NO_ACTION); + down_disabled = true; + break; + case MAXIMIZED: + left = GET_RESOURCE_STRING(IDS_SNAP_LEFT); + right = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); + up = GET_RESOURCE_STRING(IDS_NO_ACTION); + up_disabled = true; + down = GET_RESOURCE_STRING(IDS_RESTORE); + break; + case SNAPPED_TOP_LEFT: + left = GET_RESOURCE_STRING(IDS_SNAP_UPPER_RIGHT); + right = GET_RESOURCE_STRING(IDS_SNAP_UPPER_RIGHT); + up = GET_RESOURCE_STRING(IDS_MAXIMIZE); + down = GET_RESOURCE_STRING(IDS_SNAP_LEFT); + break; + case SNAPPED_LEFT: + left = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); + right = GET_RESOURCE_STRING(IDS_RESTORE); + up = GET_RESOURCE_STRING(IDS_SNAP_UPPER_LEFT); + down = GET_RESOURCE_STRING(IDS_SNAP_LOWER_LEFT); + break; + case SNAPPED_BOTTOM_LEFT: + left = GET_RESOURCE_STRING(IDS_SNAP_LOWER_RIGHT); + right = GET_RESOURCE_STRING(IDS_SNAP_LOWER_RIGHT); + up = GET_RESOURCE_STRING(IDS_SNAP_LEFT); + down = GET_RESOURCE_STRING(IDS_MINIMIZE); + break; + case SNAPPED_TOP_RIGHT: + left = GET_RESOURCE_STRING(IDS_SNAP_UPPER_LEFT); + right = GET_RESOURCE_STRING(IDS_SNAP_UPPER_LEFT); + up = GET_RESOURCE_STRING(IDS_MAXIMIZE); + down = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); + break; + case SNAPPED_RIGHT: + left = GET_RESOURCE_STRING(IDS_RESTORE); + right = GET_RESOURCE_STRING(IDS_SNAP_LEFT); + up = GET_RESOURCE_STRING(IDS_SNAP_UPPER_RIGHT); + down = GET_RESOURCE_STRING(IDS_SNAP_LOWER_RIGHT); + break; + case SNAPPED_BOTTOM_RIGHT: + left = GET_RESOURCE_STRING(IDS_SNAP_LOWER_LEFT); + right = GET_RESOURCE_STRING(IDS_SNAP_LOWER_LEFT); + up = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); + down = GET_RESOURCE_STRING(IDS_MINIMIZE); + break; + case RESTORED: + left = GET_RESOURCE_STRING(IDS_SNAP_LEFT); + right = GET_RESOURCE_STRING(IDS_SNAP_RIGHT); + up = GET_RESOURCE_STRING(IDS_MAXIMIZE); + down = GET_RESOURCE_STRING(IDS_MINIMIZE); + break; + default: + left = GET_RESOURCE_STRING(IDS_NO_ACTION); + left_disabled = true; + right = GET_RESOURCE_STRING(IDS_NO_ACTION); + right_disabled = true; + up = GET_RESOURCE_STRING(IDS_NO_ACTION); + up_disabled = true; + down = GET_RESOURCE_STRING(IDS_NO_ACTION); + down_disabled = true; + } + auto text_color = D2D1::ColorF(light_mode ? 0x222222 : 0xDDDDDD, active_window_snappable && (miniature_shown || window_state == MINIMIZED) ? 1.0f : 0.3f); + use_overlay->find_element(L"KeyUpGroup")->SetAttributeValue(L"fill-opacity", up_disabled ? 0.3f : 1.0f); + text.set_alignment_center().write(d2d_dc, text_color, use_overlay->get_maximize_label(), up); + use_overlay->find_element(L"KeyDownGroup")->SetAttributeValue(L"fill-opacity", down_disabled ? 0.3f : 1.0f); + text.write(d2d_dc, text_color, use_overlay->get_minimize_label(), down); + use_overlay->find_element(L"KeyLeftGroup")->SetAttributeValue(L"fill-opacity", left_disabled ? 0.3f : 1.0f); + text.set_alignment_right().write(d2d_dc, text_color, use_overlay->get_snap_left(), left); + use_overlay->find_element(L"KeyRightGroup")->SetAttributeValue(L"fill-opacity", right_disabled ? 0.3f : 1.0f); + text.set_alignment_left().write(d2d_dc, text_color, use_overlay->get_snap_right(), right); + } + else + { + auto time_since_start = std::chrono::high_resolution_clock::now() - shown_start_time; + if (time_since_start.count() / 1000000 > milliseconds_press_time_for_global_windows_shortcuts - milliseconds_press_time_for_taskbar_icon_shortcuts) + { + global_windows_shortcuts_shown = true; + global_windows_shortcuts_animation.reset(); } - render_arrow(arrows[(size_t)(button.keynum) - 1], button, window_rect, use_overlay->get_scale(), d2d_dc); } } diff --git a/src/modules/ShortcutGuide/ShortcutGuide/overlay_window.h b/src/modules/ShortcutGuide/ShortcutGuide/overlay_window.h index 7f9aaf6646..8d7b216a54 100644 --- a/src/modules/ShortcutGuide/ShortcutGuide/overlay_window.h +++ b/src/modules/ShortcutGuide/ShortcutGuide/overlay_window.h @@ -51,6 +51,8 @@ public: void show(HWND active_window, bool snappable); ~D2DOverlayWindow(); void apply_overlay_opacity(float opacity); + void apply_press_time_for_global_windows_shortcuts(int press_time); + void apply_press_time_for_taskbar_icon_shortcuts(int press_time); void set_theme(const std::wstring& theme); void quick_hide(); @@ -78,7 +80,11 @@ private: int monitor_dx = 0, monitor_dy = 0; D2DText text; WindowsColors colors; - Animation animation; + Animation background_animation; + Animation global_windows_shortcuts_animation; + Animation taskbar_icon_shortcuts_animation; + bool global_windows_shortcuts_shown = false; + bool taskbar_icon_shortcuts_shown = false; RECT window_rect = {}; Tasklist tasklist; std::vector tasklist_buttons; @@ -103,4 +109,6 @@ private: System } theme_setting = System; bool light_mode = true; + UINT milliseconds_press_time_for_global_windows_shortcuts = 900; + UINT milliseconds_press_time_for_taskbar_icon_shortcuts = 900; }; diff --git a/src/modules/ShortcutGuide/ShortcutGuide/shortcut_guide.cpp b/src/modules/ShortcutGuide/ShortcutGuide/shortcut_guide.cpp index db46af81ef..108b2a346a 100644 --- a/src/modules/ShortcutGuide/ShortcutGuide/shortcut_guide.cpp +++ b/src/modules/ShortcutGuide/ShortcutGuide/shortcut_guide.cpp @@ -86,7 +86,7 @@ namespace } const LPARAM eventActivateWindow = 1; - + bool wasWinPressed = false; bool isWinPressed() { @@ -132,7 +132,7 @@ namespace { event.lParam = reinterpret_cast(lParam); event.wParam = wParam; - + if (event.lParam->vkCode == VK_ESCAPE) { Logger::trace(L"ESC key was pressed"); @@ -164,14 +164,14 @@ namespace { switch (type) { - case HideWindowType::ESC_PRESSED: - return L"ESC_PRESSED"; - case HideWindowType::WIN_RELEASED: - return L"WIN_RELEASED"; - case HideWindowType::WIN_SHORTCUT_PRESSED: - return L"WIN_SHORTCUT_PRESSED"; - case HideWindowType::THE_SHORTCUT_PRESSED: - return L"THE_SHORTCUT_PRESSED"; + case HideWindowType::ESC_PRESSED: + return L"ESC_PRESSED"; + case HideWindowType::WIN_RELEASED: + return L"WIN_RELEASED"; + case HideWindowType::WIN_SHORTCUT_PRESSED: + return L"WIN_SHORTCUT_PRESSED"; + case HideWindowType::THE_SHORTCUT_PRESSED: + return L"THE_SHORTCUT_PRESSED"; } return L""; @@ -181,7 +181,7 @@ namespace OverlayWindow::OverlayWindow(HWND activeWindow) { instance = this; - this -> activeWindow = activeWindow; + this->activeWindow = activeWindow; app_name = GET_RESOURCE_STRING(IDS_SHORTCUT_GUIDE); Logger::info("Overlay Window is creating"); @@ -198,6 +198,19 @@ void OverlayWindow::ShowWindow() winkey_popup = std::make_unique(); winkey_popup->apply_overlay_opacity(((float)overlayOpacity.value) / 100.0f); winkey_popup->set_theme(theme.value); + + // The press time only takes effect when the shortcut guide is activated by pressing the win key. + if (shouldReactToPressedWinKey.value) + { + winkey_popup->apply_press_time_for_global_windows_shortcuts(windowsKeyPressTimeForGlobalWindowsShortcuts.value); + winkey_popup->apply_press_time_for_taskbar_icon_shortcuts(windowsKeyPressTimeForTaskbarIconShortcuts.value); + } + else + { + winkey_popup->apply_press_time_for_global_windows_shortcuts(0); + winkey_popup->apply_press_time_for_taskbar_icon_shortcuts(0); + } + target_state = std::make_unique(); try { @@ -254,12 +267,12 @@ OverlayWindow::~OverlayWindow() { event_waiter.reset(); } - + if (winkey_popup) { winkey_popup->hide(); } - + if (target_state) { target_state->exit(); @@ -270,7 +283,7 @@ OverlayWindow::~OverlayWindow() { winkey_popup.reset(); } - + if (keyboardHook) { UnhookWindowsHookEx(keyboardHook); @@ -310,6 +323,8 @@ void OverlayWindow::init_settings() theme.value = settings.theme; disabledApps.value = settings.disabledApps; shouldReactToPressedWinKey.value = settings.shouldReactToPressedWinKey; + windowsKeyPressTimeForGlobalWindowsShortcuts.value = settings.windowsKeyPressTimeForGlobalWindowsShortcuts; + windowsKeyPressTimeForTaskbarIconShortcuts.value = settings.windowsKeyPressTimeForTaskbarIconShortcuts; update_disabled_apps(); } @@ -419,7 +434,15 @@ ShortcutGuideSettings OverlayWindow::GetSettings() noexcept try { - settings.windowsKeyPressTime = (int)properties.GetNamedObject(WindowsKeyPressTime::name).GetNamedNumber(L"value"); + settings.windowsKeyPressTimeForGlobalWindowsShortcuts = (int)properties.GetNamedObject(WindowsKeyPressTimeForGlobalWindowsShortcuts::name).GetNamedNumber(L"value"); + } + catch (...) + { + } + + try + { + settings.windowsKeyPressTimeForTaskbarIconShortcuts = (int)properties.GetNamedObject(WindowsKeyPressTimeForTaskbarIconShortcuts::name).GetNamedNumber(L"value"); } catch (...) { diff --git a/src/modules/ShortcutGuide/ShortcutGuide/shortcut_guide.h b/src/modules/ShortcutGuide/ShortcutGuide/shortcut_guide.h index 053e02766d..1008b0ac32 100644 --- a/src/modules/ShortcutGuide/ShortcutGuide/shortcut_guide.h +++ b/src/modules/ShortcutGuide/ShortcutGuide/shortcut_guide.h @@ -84,10 +84,17 @@ private: bool value; } shouldReactToPressedWinKey; - struct WindowsKeyPressTime + struct WindowsKeyPressTimeForGlobalWindowsShortcuts { static inline PCWSTR name = L"press_time"; - } windowsKeyPressTime; + int value; + } windowsKeyPressTimeForGlobalWindowsShortcuts; + + struct WindowsKeyPressTimeForTaskbarIconShortcuts + { + static inline PCWSTR name = L"press_time_for_taskbar_icon_shortcuts"; + int value; + } windowsKeyPressTimeForTaskbarIconShortcuts; struct OpenShortcut { diff --git a/src/modules/ShortcutGuide/ShortcutGuide/trace.cpp b/src/modules/ShortcutGuide/ShortcutGuide/trace.cpp index 2b7e9a123c..b68e7bbcad 100644 --- a/src/modules/ShortcutGuide/ShortcutGuide/trace.cpp +++ b/src/modules/ShortcutGuide/ShortcutGuide/trace.cpp @@ -40,7 +40,8 @@ void Trace::SendSettings(ShortcutGuideSettings settings) noexcept TraceLoggingWideString(settings.theme.c_str(), "Theme"), TraceLoggingWideString(settings.disabledApps.c_str(), "DisabledApps"), TraceLoggingBoolean(settings.shouldReactToPressedWinKey, "ShouldReactToPressedWinKey"), - TraceLoggingInt32(settings.windowsKeyPressTime, "WindowsKeyPressTime"), + TraceLoggingInt32(settings.windowsKeyPressTimeForGlobalWindowsShortcuts, "WindowsKeyPressTimeForGlobalWindowsShortcuts"), + TraceLoggingInt32(settings.windowsKeyPressTimeForTaskbarIconShortcuts, "WindowsKeyPressTimeForTaskbarIconShortcuts"), ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); diff --git a/src/modules/ShortcutGuide/ShortcutGuideModuleInterface/dllmain.cpp b/src/modules/ShortcutGuide/ShortcutGuideModuleInterface/dllmain.cpp index 01697d633a..a7d7a1cc1b 100644 --- a/src/modules/ShortcutGuide/ShortcutGuideModuleInterface/dllmain.cpp +++ b/src/modules/ShortcutGuide/ShortcutGuideModuleInterface/dllmain.cpp @@ -171,7 +171,7 @@ public: virtual UINT milliseconds_win_key_must_be_pressed() override { - return m_millisecondsWinKeyShouldBePressed; + return std::min(m_millisecondsWinKeyPressTimeForGlobalWindowsShortcuts, m_millisecondsWinKeyPressTimeForTaskbarIconShortcuts); } private: @@ -185,9 +185,11 @@ private: HotkeyEx m_hotkey; // If the module should be activated through the legacy pressing windows key behavior. - const UINT DEFAULT_MILLISECONDS_WIN_KEY_SHOULD_BE_PRESSED = 900; + const UINT DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_GLOBAL_WINDOWS_SHORTCUTS = 900; + const UINT DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_TASKBAR_ICON_SHORTCUTS = 900; bool m_shouldReactToPressedWinKey = false; - UINT m_millisecondsWinKeyShouldBePressed = DEFAULT_MILLISECONDS_WIN_KEY_SHOULD_BE_PRESSED; + UINT m_millisecondsWinKeyPressTimeForGlobalWindowsShortcuts = DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_GLOBAL_WINDOWS_SHORTCUTS; + UINT m_millisecondsWinKeyPressTimeForTaskbarIconShortcuts = DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_TASKBAR_ICON_SHORTCUTS; HANDLE exitEvent; @@ -280,7 +282,8 @@ private: void ParseSettings(PowerToysSettings::PowerToyValues& settings) { m_shouldReactToPressedWinKey = false; - m_millisecondsWinKeyShouldBePressed = DEFAULT_MILLISECONDS_WIN_KEY_SHOULD_BE_PRESSED; + m_millisecondsWinKeyPressTimeForGlobalWindowsShortcuts = DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_GLOBAL_WINDOWS_SHORTCUTS; + m_millisecondsWinKeyPressTimeForTaskbarIconShortcuts = DEFAULT_MILLISECONDS_WIN_KEY_PRESS_TIME_FOR_TASKBAR_ICON_SHORTCUTS; auto settingsObject = settings.get_raw_json(); if (settingsObject.GetView().Size()) @@ -322,8 +325,10 @@ private: // Parse Legacy windows key press behavior settings auto jsonUseLegacyWinKeyBehaviorObject = settingsObject.GetNamedObject(L"properties").GetNamedObject(L"use_legacy_press_win_key_behavior"); m_shouldReactToPressedWinKey = (bool)jsonUseLegacyWinKeyBehaviorObject.GetNamedBoolean(L"value"); - auto jsonPressTimeObject = settingsObject.GetNamedObject(L"properties").GetNamedObject(L"press_time"); - m_millisecondsWinKeyShouldBePressed = (UINT)jsonPressTimeObject.GetNamedNumber(L"value"); + auto jsonPressTimeForGlobalWindowsShortcutsObject = settingsObject.GetNamedObject(L"properties").GetNamedObject(L"press_time"); + auto jsonPressTimeForTaskbarIconShortcutsObject = settingsObject.GetNamedObject(L"properties").GetNamedObject(L"press_time_for_taskbar_icon_shortcuts"); + m_millisecondsWinKeyPressTimeForGlobalWindowsShortcuts = (UINT)jsonPressTimeForGlobalWindowsShortcutsObject.GetNamedNumber(L"value"); + m_millisecondsWinKeyPressTimeForTaskbarIconShortcuts = (UINT)jsonPressTimeForTaskbarIconShortcutsObject.GetNamedNumber(L"value"); } catch (...) { diff --git a/src/settings-ui/Settings.UI.Library/ShortcutGuideProperties.cs b/src/settings-ui/Settings.UI.Library/ShortcutGuideProperties.cs index 83db634d20..7112b5ae80 100644 --- a/src/settings-ui/Settings.UI.Library/ShortcutGuideProperties.cs +++ b/src/settings-ui/Settings.UI.Library/ShortcutGuideProperties.cs @@ -12,7 +12,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library { OverlayOpacity = new IntProperty(90); UseLegacyPressWinKeyBehavior = new BoolProperty(false); - PressTime = new IntProperty(900); + PressTimeForGlobalWindowsShortcuts = new IntProperty(900); + PressTimeForTaskbarIconShortcuts = new IntProperty(900); Theme = new StringProperty("system"); DisabledApps = new StringProperty(); OpenShortcutGuide = new HotkeySettings(true, false, false, true, 0xBF); @@ -28,7 +29,10 @@ namespace Microsoft.PowerToys.Settings.UI.Library public BoolProperty UseLegacyPressWinKeyBehavior { get; set; } [JsonPropertyName("press_time")] - public IntProperty PressTime { get; set; } + public IntProperty PressTimeForGlobalWindowsShortcuts { get; set; } + + [JsonPropertyName("press_time_for_taskbar_icon_shortcuts")] + public IntProperty PressTimeForTaskbarIconShortcuts { get; set; } [JsonPropertyName("theme")] public StringProperty Theme { get; set; } diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw index 950f2dfe9e..22f3003c36 100644 --- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw @@ -814,13 +814,10 @@ Shows a help overlay with Windows shortcuts. - - Press duration before showing (ms) + + Press duration before showing global Windows shortcuts (ms) ms = milliseconds - - How long to press the Windows key to activate the module - Activation method @@ -2685,6 +2682,10 @@ Activate by holding the key for the character you want to add an accent to, then Launch as administrator + + Press duration before showing taskbar icon shortcuts (ms) + ms = milliseconds + A Windows shell extension to find out which processes are using the selected files and directories. diff --git a/src/settings-ui/Settings.UI/ViewModels/ShortcutGuideViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/ShortcutGuideViewModel.cs index 2f1715830b..43c6091cac 100644 --- a/src/settings-ui/Settings.UI/ViewModels/ShortcutGuideViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/ShortcutGuideViewModel.cs @@ -66,7 +66,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels } _useLegacyPressWinKeyBehavior = Settings.Properties.UseLegacyPressWinKeyBehavior.Value; - _pressTime = Settings.Properties.PressTime.Value; + _pressTimeForGlobalWindowsShortcuts = Settings.Properties.PressTimeForGlobalWindowsShortcuts.Value; + _pressTimeForTaskbarIconShortcuts = Settings.Properties.PressTimeForTaskbarIconShortcuts.Value; _opacity = Settings.Properties.OverlayOpacity.Value; _disabledApps = Settings.Properties.DisabledApps.Value; @@ -83,7 +84,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels private bool _isEnabled; private int _themeIndex; private bool _useLegacyPressWinKeyBehavior; - private int _pressTime; + private int _pressTimeForGlobalWindowsShortcuts; + private int _pressTimeForTaskbarIconShortcuts; private int _opacity; public bool IsEnabled @@ -201,15 +203,33 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels { get { - return _pressTime; + return _pressTimeForGlobalWindowsShortcuts; } set { - if (_pressTime != value) + if (_pressTimeForGlobalWindowsShortcuts != value) { - _pressTime = value; - Settings.Properties.PressTime.Value = value; + _pressTimeForGlobalWindowsShortcuts = value; + Settings.Properties.PressTimeForGlobalWindowsShortcuts.Value = value; + NotifyPropertyChanged(); + } + } + } + + public int DelayTime + { + get + { + return _pressTimeForTaskbarIconShortcuts; + } + + set + { + if (_pressTimeForTaskbarIconShortcuts != value) + { + _pressTimeForTaskbarIconShortcuts = value; + Settings.Properties.PressTimeForTaskbarIconShortcuts.Value = value; NotifyPropertyChanged(); } } diff --git a/src/settings-ui/Settings.UI/Views/ShortcutGuidePage.xaml b/src/settings-ui/Settings.UI/Views/ShortcutGuidePage.xaml index 2201f6a057..9a13ed3bc4 100644 --- a/src/settings-ui/Settings.UI/Views/ShortcutGuidePage.xaml +++ b/src/settings-ui/Settings.UI/Views/ShortcutGuidePage.xaml @@ -53,7 +53,7 @@ - + + + + + + +