Skip to content

Commit

Permalink
Fix tab navigation in settings window
Browse files Browse the repository at this point in the history
- Fixes tab key not being captured
- Github: fixes #71
  • Loading branch information
dsafa committed Apr 10, 2019
1 parent 658ed3b commit b949fac
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/AudioBand/AudioBand.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
<DependentUpon>MainControl.cs</DependentUpon>
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Messages\FocusChangedMessage.cs" />
<Compile Include="Models\AlbumArt.cs" />
<Compile Include="Models\AlbumArtPopup.cs" />
<Compile Include="Models\AudioBand.cs" />
Expand Down
71 changes: 66 additions & 5 deletions src/AudioBand/CSDeskBand/CSDeskBand.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// <autogenerated/>
// Define the symbol DESKBAND_WINFORMS for winforms or DESKBAND_WPF for wpf
// For wpf make sure to add a reference to WindowsFormsIntegration.dll, System.Windows.Forms and System.Drawing
// VERSION 3.0
// LICENSE: https://raw.githubusercontent.com/dsafa/CSDeskBand/master/LICENSE
#pragma warning disable 1591
namespace CSDeskBand
{
Expand Down Expand Up @@ -186,7 +188,7 @@ public int GetCompositionState(out bool pfCompositionEnabled)
/// <inheritdoc/>
public int SetSite([In, MarshalAs(UnmanagedType.IUnknown)] object pUnkSite)
{
// .net will automatically release when garbage collected
// Let gc release old site
_parentSite = null;

// pUnkSite null means deskband was closed
Expand Down Expand Up @@ -343,19 +345,31 @@ public void CloseDeskBand()
/// <inheritdoc/>
public int UIActivateIO(int fActivate, ref MSG msg)
{
_provider.HasFocus = fActivate != 0;
UpdateFocus(_provider.HasFocus);
return HRESULT.S_OK;
}

/// <inheritdoc/>
public int HasFocusIO()
{
return HRESULT.E_NOTIMPL;
return _provider.HasFocus ? HRESULT.S_OK : HRESULT.S_FALSE;
}

/// <inheritdoc/>
public int TranslateAcceleratorIO(ref MSG msg)
{
return HRESULT.E_NOTIMPL;
return HRESULT.S_OK;
}

/// <summary>
/// Updates the focus on the deskband. Explorer will call <see cref="UIActivateIO(int, ref MSG)"/> for example if tabbing when the taskbar is focused.
/// But if focus is acquired without in other ways, then explorer isn't aware of it and <see cref="IInputObjectSite.OnFocusChangeIS(object, int)"/> needs to be called.
/// </summary>
/// <param name="focused">True if focused.</param>
public void UpdateFocus(bool focused)
{
(_parentSite as IInputObjectSite)?.OnFocusChangeIS(this, focused ? 1 : 0);
}

private void Options_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
Expand Down Expand Up @@ -766,7 +780,6 @@ internal sealed class CSDeskBandRegistrationAttribute : Attribute
namespace CSDeskBand
{
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using CSDeskBand.Interop;
Expand Down Expand Up @@ -828,6 +841,27 @@ private static void Unregister(Type t)
/// </summary>
public Guid Guid => GetType().GUID;

public bool HasFocus
{
get => Control?.ContainsFocus ?? false;
set
{
if (value)
{
Control?.Focus();
}
}
}

/// <summary>
/// Updates the focus on this deskband.
/// </summary>
/// <param name="focused"><see langword="true"/> if focused.</param>
public void UpdateFocus(bool focused)
{
_impl.UpdateFocus(focused);
}

/// <summary>
/// Handle closing of the deskband.
/// </summary>
Expand Down Expand Up @@ -962,7 +996,6 @@ public int TranslateAcceleratorIO(ref MSG msg)
namespace CSDeskBand
{
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
Expand Down Expand Up @@ -1027,6 +1060,27 @@ private static void Unregister(Type t)
/// </summary>
public Guid Guid => GetType().GUID;

public bool HasFocus
{
get => UIElement?.IsKeyboardFocusWithin ?? false;
set
{
if (value)
{
UIElement?.Focus();
}
}
}

/// <summary>
/// Updates the focus on this deskband.
/// </summary>
/// <param name="focused"><see langword="true"/> if focused.</param>
public void UpdateFocus(bool focused)
{
_impl.UpdateFocus(focused);
}

/// <summary>
/// Handle closing of the deskband.
/// </summary>
Expand Down Expand Up @@ -1357,6 +1411,7 @@ internal interface IDeskBandProvider
IntPtr Handle { get; }
CSDeskBandOptions Options { get; }
Guid Guid { get; }
bool HasFocus { get; set; }
}
}
namespace CSDeskBand
Expand Down Expand Up @@ -2004,6 +2059,12 @@ internal class User32
[DllImport("user32.dll")]
public static extern IntPtr CreatePopupMenu();

[DllImport("user32.dll")]
public static extern bool TranslateMessage([In] ref MSG lpMsg);

[DllImport("user32.dll")]
public static extern IntPtr DispatchMessage([In] ref MSG lpmsg);

public static int HiWord(int val)
{
return Convert.ToInt32(BitConverter.ToInt16(BitConverter.GetBytes(val), 2));
Expand Down
12 changes: 12 additions & 0 deletions src/AudioBand/Deskband.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
using System.Windows.Forms;
using AudioBand.AudioSource;
using AudioBand.Logging;
using AudioBand.Messages;
using AudioBand.Models;
using AudioBand.Resources;
using AudioBand.Settings;
using AudioBand.ViewModels;
using AudioBand.Views.Wpf;
using CSDeskBand;
using PubSub.Extension;
using SimpleInjector;

namespace AudioBand
Expand Down Expand Up @@ -41,6 +43,7 @@ public Deskband()
AppDomain.CurrentDomain.UnhandledException += (sender, args) => AudioBandLogManager.GetLogger("AudioBand").Error((Exception)args.ExceptionObject, "Unhandled Exception");
ConfigureDependencies();
_mainControl = _container.GetInstance<MainControl>();
this.Subscribe<FocusChangedMessage>(FocusCaptured);
}

/// <inheritdoc/>
Expand Down Expand Up @@ -92,5 +95,14 @@ private void ConfigureDependencies()
throw;
}
}

private void FocusCaptured(FocusChangedMessage msg)
{
// Capture focus so that tab button is captured
if (msg == FocusChangedMessage.FocusCaptured)
{
UpdateFocus(true);
}
}
}
}
13 changes: 13 additions & 0 deletions src/AudioBand/Messages/FocusChangedMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace AudioBand.Messages
{
/// <summary>
/// Messages for focus change
/// </summary>
public enum FocusChangedMessage
{
/// <summary>
/// Focus captured
/// </summary>
FocusCaptured
}
}
10 changes: 10 additions & 0 deletions src/AudioBand/Views/Wpf/Resources/Style.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@
</Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Unfocused"/>
<VisualState x:Name="Focused">
<Storyboard>
<ColorAnimation Storyboard.TargetName="Border" Storyboard.TargetProperty="(BorderBrush).(SolidColorBrush.Color)"
To="{StaticResource BorderHoverColor}" Duration="0:0:0.1"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
Expand All @@ -123,6 +132,7 @@
<Setter Property="Background" Value="Transparent"/>
</Style>
<Style x:Key="NavigationPaneListBoxItem" TargetType="{x:Type ListBoxItem}">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
Expand Down
12 changes: 7 additions & 5 deletions src/AudioBand/Views/Wpf/SettingsWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</fw:AcrylicWindow.Resources>
<DockPanel LastChildFill="True">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<DockPanel LastChildFill="True" KeyboardNavigation.IsTabStop="False">
<ScrollViewer VerticalScrollBarVisibility="Auto" IsTabStop="False">
<StackPanel DockPanel.Dock="Left" Background="Transparent" x:Name="NavigationPane">
<RadioButton Style="{StaticResource NavigationPaneRadioButton}" GroupName="nav" Content="{StaticResource GeneralSettingsTab}"
Command="{Binding SelectViewModelCommand}" CommandParameter="{Binding ElementName=Window, Path=AudioBandVM}"/>
Expand Down Expand Up @@ -64,7 +64,8 @@
</Grid>
</Expander.Header>
<ListBox Background="Transparent" ItemsSource="{Binding ElementName=Window, Path=CustomLabelsVM.CustomLabels}"
ItemContainerStyle="{StaticResource NavigationPaneListBoxItem}">
ItemContainerStyle="{StaticResource NavigationPaneListBoxItem}"
KeyboardNavigation.TabNavigation="Local">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton Style="{StaticResource NavigationPaneRadioButton}"
Expand Down Expand Up @@ -120,8 +121,9 @@
<Button Margin="8" Content="{StaticResource CancelButtonText}" IsCancel="True" Width="100"
Command="{Binding ElementName=Window, Path=CancelCloseCommand}"/>
</StackPanel>
<ScrollViewer Background="White" Padding="20" SnapsToDevicePixels="True" VerticalScrollBarVisibility="Auto">
<ContentControl Content="{Binding SelectedVM}" BorderThickness="0">
<ScrollViewer Background="White" Padding="20" SnapsToDevicePixels="True" VerticalScrollBarVisibility="Auto"
IsTabStop="False">
<ContentControl Content="{Binding SelectedVM}" BorderThickness="0" IsTabStop="False">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewmodels:AudioBandVM}">
<local:GeneralSettingsView DataContext="{Binding}"/>
Expand Down
30 changes: 30 additions & 0 deletions src/AudioBand/Views/Wpf/SettingsWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Forms.Integration;
using System.Windows.Input;
using AudioBand.Commands;
using AudioBand.Messages;
using AudioBand.ViewModels;
Expand Down Expand Up @@ -72,6 +74,8 @@ public SettingsWindow(
InitializeComponent();
DataContext = vm;
_vm = vm;

Activated += OnActivated;
}

/// <inheritdoc/>
Expand Down Expand Up @@ -126,6 +130,7 @@ public void ShowWindow()
_shouldSave = false;
_vm.SelectedVM?.BeginEdit();
Show();
Activate();
}

/// <inheritdoc/>
Expand All @@ -148,6 +153,26 @@ protected override void OnClosing(CancelEventArgs e)
Hide();
}

/// <summary>
/// Manually handle tab navigation since deskband focus is weird
/// </summary>
/// <param name="e">Key event</param>
protected override void OnPreviewKeyUp(KeyEventArgs e)
{
base.OnPreviewKeyUp(e);
if (e.Key != Key.Tab)
{
return;
}

var focusedElement = Keyboard.FocusedElement as UIElement;
FocusNavigationDirection direction = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift)
? FocusNavigationDirection.Previous
: FocusNavigationDirection.Next;

focusedElement?.MoveFocus(new TraversalRequest(direction));
}

// Problem with late binding. Fuslogvw shows its not probing the original location.
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
Expand All @@ -162,6 +187,11 @@ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEven
return File.Exists(filename) ? Assembly.LoadFrom(filename) : null;
}

private void OnActivated(object sender, EventArgs e)
{
this.Publish(FocusChangedMessage.FocusCaptured);
}

private void SaveCloseCommandOnExecute(object o)
{
_shouldSave = true;
Expand Down

0 comments on commit b949fac

Please sign in to comment.