Skip to content

Commit

Permalink
Fixes handling/swallowing of access-keys and input bindings #258
Browse files Browse the repository at this point in the history
  • Loading branch information
batzen committed Feb 24, 2016
1 parent fcade77 commit 0c6dd8f
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 7 deletions.
1 change: 1 addition & 0 deletions Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
<Compile Include="IHeaderedControl.cs" />
<Compile Include="Internal\FocusWrapper.cs" />
<Compile Include="Internal\ItemsControlHelper.cs" />
<Compile Include="Internal\KeyEventUtility.cs" />
<Compile Include="Internal\UIHelper.cs" />
<Compile Include="Services\ContextMenuService.cs" />
<Compile Include="Converters\ApplicationMenuRightContentExtractorConverter.cs" />
Expand Down
1 change: 1 addition & 0 deletions Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
<Compile Include="IHeaderedControl.cs" />
<Compile Include="Internal\FocusWrapper.cs" />
<Compile Include="Internal\ItemsControlHelper.cs" />
<Compile Include="Internal\KeyEventUtility.cs" />
<Compile Include="Internal\UIHelper.cs" />
<Compile Include="Services\ContextMenuService.cs" />
<Compile Include="Converters\ApplicationMenuRightContentExtractorConverter.cs" />
Expand Down
34 changes: 34 additions & 0 deletions Fluent.Ribbon/Internal/KeyEventUtility.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace Fluent.Internal
{
using System.Windows.Input;

internal static class KeyEventUtility
{
public static string GetStringFromKey(Key key)
{
var keyboardState = new byte[256];
if (NativeMethods.GetKeyboardState(keyboardState) == false)
{
return null;
}

var virtualKey = KeyInterop.VirtualKeyFromKey(key);
var scanCode = NativeMethods.MapVirtualKey((uint)virtualKey, NativeMethods.MapType.MAPVK_VK_TO_VSC);
var chars = new char[1];

var result = NativeMethods.ToUnicode((uint)virtualKey, scanCode, keyboardState, chars, chars.Length, 0);
switch (result)
{
case -1:
case 0:
return null;

case 1:
return chars[0].ToString();

default:
return null;
}
}
}
}
19 changes: 19 additions & 0 deletions Fluent.Ribbon/Internal/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,25 @@ public static bool _ModifyStyle(this IntPtr _hwnd, WS removeStyle, WS addStyle)
return true;
}

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern int ToUnicode(uint virtualKey, uint scanCode, byte[] keyStates, [MarshalAs(UnmanagedType.LPArray)] [Out] char[] chars, int charMaxCount, uint flags);

[DllImport("user32.dll")]
internal static extern bool GetKeyboardState(byte[] lpKeyState);

[DllImport("user32.dll")]
internal static extern uint MapVirtualKey(uint uCode, MapType uMapType);

// ReSharper disable InconsistentNaming
internal enum MapType : uint
{
MAPVK_VK_TO_VSC = 0x0,
MAPVK_VSC_TO_VK = 0x1,
MAPVK_VK_TO_CHAR = 0x2,
MAPVK_VSC_TO_VK_EX = 0x3,
}
// ReSharper restore InconsistentNaming

/// <summary>
/// GetWindowLong values, GWL_*
/// </summary>
Expand Down
29 changes: 22 additions & 7 deletions Fluent.Ribbon/Services/KeyTipService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ internal class KeyTipService
// Attached HWND source
private HwndSource attachedHwndSource;

private static readonly KeyConverter keyConverter = new KeyConverter();
private string currentUserInput;

/// <summary>
Expand Down Expand Up @@ -171,13 +170,15 @@ private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, re

private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.IsRepeat)
if (e.IsRepeat
|| e.Handled)
{
return;
}

if (this.ribbon.IsCollapsed
|| this.ribbon.IsEnabled == false)
|| this.ribbon.IsEnabled == false
|| this.window.IsActive == false)
{
return;
}
Expand Down Expand Up @@ -224,7 +225,9 @@ private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
}

var actualKey = e.Key == Key.System ? e.SystemKey : e.Key;
var isKeyRealInput = ((actualKey >= Key.A && actualKey <= Key.Z) || (actualKey >= Key.D0 && actualKey <= Key.D9) || (actualKey >= Key.NumPad0 && actualKey <= Key.NumPad9));
// we need to get the real string input for the key because of keys like ä,ö,ü #258
var key = KeyEventUtility.GetStringFromKey(actualKey);
var isKeyRealInput = string.IsNullOrEmpty(key) == false;

// Don't do anything and let WPF handle the rest
if (isKeyRealInput == false)
Expand All @@ -240,12 +243,15 @@ private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
return;
}

var shownImmediately = false;

// Should we show the keytips and immediately react to key?
if (this.activeAdornerChain == null
|| this.activeAdornerChain.IsAdornerChainAlive == false
|| this.activeAdornerChain.AreAnyKeyTipsVisible == false)
{
this.ShowImmediatly();
shownImmediately = true;
}

if (this.activeAdornerChain == null)
Expand All @@ -254,11 +260,18 @@ private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
}

var previousInput = this.currentUserInput;
this.currentUserInput += keyConverter.ConvertToString(actualKey);
this.currentUserInput += key;

// If no key tips match the current input, continue with the previously entered and still correct keys.
if (this.activeAdornerChain.ActiveKeyTipAdorner.ContainsKeyTipStartingWith(this.currentUserInput) == false)
{
// Handles access-keys #258
if (shownImmediately)
{
this.activeAdornerChain?.Terminate();
return;
}

// If no key tips match the current input, continue with the previously entered and still correct keys.
this.currentUserInput = previousInput;
System.Media.SystemSounds.Beep.Play();
e.Handled = true;
Expand All @@ -282,8 +295,10 @@ private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
private void OnWindowKeyUp(object sender, KeyEventArgs e)
{
if (this.ribbon.IsCollapsed
|| this.ribbon.IsEnabled == false)
|| this.ribbon.IsEnabled == false
|| this.window.IsActive == false)
{
this.activeAdornerChain?.Terminate();
return;
}

Expand Down

0 comments on commit 0c6dd8f

Please sign in to comment.