diff --git a/README.md b/README.md
index 9aec854..3a891f6 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ Download the compiled Windows release from:
- System tray launcher
- Global hotkey, default `Ctrl+Alt+Space`
- Search/filter in the launcher popup with parent menu context
+- Keyboard navigation in the launcher popup
- Recent items section for quickly relaunching entries
- Nested menus, drag/drop ordering, and drag/drop item creation in Settings
- Right-click launcher entries to edit them in Settings
diff --git a/TaskbarLauncher.csproj b/TaskbarLauncher.csproj
index 1012f94..da33b73 100644
--- a/TaskbarLauncher.csproj
+++ b/TaskbarLauncher.csproj
@@ -12,8 +12,8 @@
Ray Berezowski
Assets\AppIcon.ico
1.0.1
- 1.0.1.14
- 1.0.1.14
+ 1.0.1.15
+ 1.0.1.15
1.0.1
diff --git a/Views/LauncherPopup.xaml.cs b/Views/LauncherPopup.xaml.cs
index 4893c01..4611b4e 100644
--- a/Views/LauncherPopup.xaml.cs
+++ b/Views/LauncherPopup.xaml.cs
@@ -164,19 +164,7 @@ public partial class LauncherPopup : Window
button.ContextMenu = CreateItemContextMenu(item);
}
- button.KeyDown += (_, e) =>
- {
- if (e.Key == Key.Enter)
- {
- launchItem(item);
- e.Handled = true;
- }
- else if (e.Key == Key.Escape)
- {
- Close();
- e.Handled = true;
- }
- };
+ button.KeyDown += LaunchButton_KeyDown;
visibleLaunchButtons.Add(button);
return button;
}
@@ -356,19 +344,7 @@ public partial class LauncherPopup : Window
};
button.Click += (_, _) => launchItem(match.Item);
- button.KeyDown += (_, e) =>
- {
- if (e.Key == Key.Enter)
- {
- launchItem(match.Item);
- e.Handled = true;
- }
- else if (e.Key == Key.Escape)
- {
- Close();
- e.Handled = true;
- }
- };
+ button.KeyDown += LaunchButton_KeyDown;
visibleLaunchButtons.Add(button);
return button;
@@ -437,14 +413,112 @@ public partial class LauncherPopup : Window
return;
}
- if (e.Key == Key.Down && visibleLaunchButtons.FirstOrDefault() is System.Windows.Controls.Button firstButton)
+ if (e.Key == Key.Down)
{
- Keyboard.ClearFocus();
- firstButton.Focus();
+ FocusLaunchButton(0);
+ e.Handled = true;
+ return;
+ }
+
+ if (e.Key == Key.Up)
+ {
+ FocusLaunchButton(visibleLaunchButtons.Count - 1);
+ e.Handled = true;
+ return;
+ }
+
+ if (e.Key == Key.Home)
+ {
+ SearchBox.CaretIndex = 0;
+ e.Handled = true;
+ return;
+ }
+
+ if (e.Key == Key.End)
+ {
+ SearchBox.CaretIndex = SearchBox.Text.Length;
e.Handled = true;
}
}
+ private void LaunchButton_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
+ {
+ if (sender is not System.Windows.Controls.Button button)
+ {
+ return;
+ }
+
+ if (e.Key == Key.Enter && button.Tag is LauncherItem item)
+ {
+ launchItem(item);
+ e.Handled = true;
+ return;
+ }
+
+ if (e.Key == Key.Escape)
+ {
+ Close();
+ e.Handled = true;
+ return;
+ }
+
+ int index = visibleLaunchButtons.IndexOf(button);
+ if (index < 0)
+ {
+ return;
+ }
+
+ if (e.Key == Key.Down)
+ {
+ FocusLaunchButton(index + 1);
+ e.Handled = true;
+ return;
+ }
+
+ if (e.Key == Key.Up)
+ {
+ if (index == 0)
+ {
+ SearchBox.Focus();
+ SearchBox.CaretIndex = SearchBox.Text.Length;
+ }
+ else
+ {
+ FocusLaunchButton(index - 1);
+ }
+
+ e.Handled = true;
+ return;
+ }
+
+ if (e.Key == Key.Home)
+ {
+ FocusLaunchButton(0);
+ e.Handled = true;
+ return;
+ }
+
+ if (e.Key == Key.End)
+ {
+ FocusLaunchButton(visibleLaunchButtons.Count - 1);
+ e.Handled = true;
+ }
+ }
+
+ private void FocusLaunchButton(int index)
+ {
+ if (visibleLaunchButtons.Count == 0)
+ {
+ return;
+ }
+
+ int clampedIndex = Math.Clamp(index, 0, visibleLaunchButtons.Count - 1);
+ System.Windows.Controls.Button button = visibleLaunchButtons[clampedIndex];
+ Keyboard.ClearFocus();
+ button.Focus();
+ button.BringIntoView();
+ }
+
protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e)
{
if (e.Key == Key.Escape)
diff --git a/docs/INSTALL.md b/docs/INSTALL.md
index 01350cd..759bf1f 100644
--- a/docs/INSTALL.md
+++ b/docs/INSTALL.md
@@ -28,6 +28,8 @@ Recently launched entries appear in the launcher popup under **Recent**.
Search results include the parent menu path when an item is inside a menu.
+Use arrow keys, Home, End, Enter, and Escape to navigate the launcher popup from the keyboard.
+
## Configure
Open the tray menu and choose **Settings**.