how to capture the '#' character on different locale keyboards in WPF/C#?
The function below, GetCharFromKey(Key key) will do the trick.
It uses a series of win32 calls to decode the key pressed:
get the virtual key from WPF key
get the scan code from the virtual key
get your unicode character
This old post describes it in a bit more detail.
public enum MapType : uint
{
MAPVK_VK_TO_VSC = 0x0,
MAPVK_VSC_TO_VK = 0x1,
MAPVK_VK_TO_CHAR = 0x2,
MAPVK_VSC_TO_VK_EX = 0x3,
}
[DllImport("user32.dll")]
public static extern int ToUnicode(
uint wVirtKey,
uint wScanCode,
byte[] lpKeyState,
[Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)]
StringBuilder pwszBuff,
int cchBuff,
uint wFlags);
[DllImport("user32.dll")]
public static extern bool GetKeyboardState(byte[] lpKeyState);
[DllImport("user32.dll")]
public static extern uint MapVirtualKey(uint uCode, MapType uMapType);
public static char GetCharFromKey(Key key)
{
char ch = ' ';
int virtualKey = KeyInterop.VirtualKeyFromKey(key);
byte[] keyboardState = new byte[256];
GetKeyboardState(keyboardState);
uint scanCode = MapVirtualKey((uint)virtualKey, MapType.MAPVK_VK_TO_VSC);
StringBuilder stringBuilder = new StringBuilder(2);
int result = ToUnicode((uint)virtualKey, scanCode, keyboardState, stringBuilder, stringBuilder.Capacity, 0);
switch (result)
{
case -1:
break;
case 0:
break;
case 1:
{
ch = stringBuilder[0];
break;
}
default:
{
ch = stringBuilder[0];
break;
}
}
return ch;
}
Global keyboard capture in C# application
Stephen Toub wrote a great article on implementing global keyboard hooks in C#:
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
How can i generate a localized keyboard shortcut in C# / WPF?
I had the same problem myself and checked the WPF source code. Sadly, strings like "Ctrl" are in fact hardcoded.
So my idea was to simply use the WindowsForms classes for displaying shortcut strings. You can do this with the following code (you could use this for a derived RoutedCommand class that automatically replaces all shortcut keys with a new display string):
private void LocalizeShortcuts()
{
foreach (KeyGesture keyGuesture in this.InputGestures.OfType<KeyGesture>().ToArray())
{
this.InputGestures.Remove(keyGuesture);
System.Windows.Forms.Keys formsKey = (Keys)KeyInterop.VirtualKeyFromKey(keyGuesture.Key);
if ((keyGuesture.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt)
{
formsKey |= Keys.Alt;
}
if ((keyGuesture.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
formsKey |= Keys.Control;
}
if ((keyGuesture.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
{
formsKey |= Keys.Shift;
}
string keyDisplayString = TypeDescriptor.GetConverter(typeof(Keys)).ConvertToString(formsKey);
this.InputGestures.Add(new KeyGesture(keyGuesture.Key, keyGuesture.Modifiers, keyDisplayString));
}
}
How to show button is pressed in UI for combination keys
This works for me:
//Make the button to have "pressed" feel when the corresponding key is pressed
private void NumDisplayBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift))
{
if (e.Key == Key.D3)
HashBtn.Style = (Style) FindResource("PressedButtonStyle");
if (e.Key == Key.D8)
StarBtn.Style = (Style) FindResource("PressedButtonStyle");
}
switch (e.Key)
{
case Key.D0:
case Key.NumPad0:
ZeroBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D1:
case Key.NumPad1:
OneBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D2:
case Key.NumPad2:
TwoBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D3:
case Key.NumPad3:
{
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
ThreeBtn.Style = (Style) FindResource("ButtonStyle4");
else
ThreeBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
}
case Key.D4:
case Key.NumPad4:
FourBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D5:
case Key.NumPad5:
FiveBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D6:
case Key.NumPad6:
SixBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D7:
case Key.NumPad7:
SevenBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
case Key.D8:
case Key.NumPad8:
{
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
EightBtn.Style = (Style) FindResource("ButtonStyle4");
else
EightBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
}
case Key.D9:
case Key.NumPad9:
NineBtn.Style = (Style) FindResource("PressedButtonStyle");
break;
default:
break;
}
}
//Return back to its original style
private void NumDisplayBox_PreviewKeyUp(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.D0:
case Key.NumPad0:
ZeroBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D1:
case Key.NumPad1:
OneBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D2:
case Key.NumPad2:
TwoBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D3:
case Key.NumPad3:
ThreeBtn.Style = (Style) FindResource("ButtonStyle4");
HashBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D4:
case Key.NumPad4:
FourBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D5:
case Key.NumPad5:
FiveBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D6:
case Key.NumPad6:
SixBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D7:
case Key.NumPad7:
SevenBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D8:
case Key.NumPad8:
EightBtn.Style = (Style) FindResource("ButtonStyle4");
StarBtn.Style = (Style) FindResource("ButtonStyle4");
break;
case Key.D9:
case Key.NumPad9:
NineBtn.Style = (Style) FindResource("ButtonStyle4");
break;
default:
break;
}
}
Detect if any key is pressed in C# (not A, B, but any)
[DllImport("user32.dll", EntryPoint = "GetKeyboardState", SetLastError = true)]
private static extern bool NativeGetKeyboardState([Out] byte[] keyStates);
private static bool GetKeyboardState(byte[] keyStates)
{
if (keyStates == null)
throw new ArgumentNullException("keyState");
if (keyStates.Length != 256)
throw new ArgumentException("The buffer must be 256 bytes long.", "keyState");
return NativeGetKeyboardState(keyStates);
}
private static byte[] GetKeyboardState()
{
byte[] keyStates = new byte[256];
if (!GetKeyboardState(keyStates))
throw new Win32Exception(Marshal.GetLastWin32Error());
return keyStates;
}
private static bool AnyKeyPressed()
{
byte[] keyState = GetKeyboardState();
// skip the mouse buttons
return keyState.Skip(8).Any(state => (state & 0x80) != 0);
}
Capture key press in whole application
You could use something like this gist to register a global hook. It will fire whenever the given keys are pressed while your application is running. You can use it in your App
class like this:
public partial class App
{
private HotKey _hotKey;
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
RegisterHotKeys();
}
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
UnregisterHotKeys();
}
private void RegisterHotKeys()
{
if (_hotKey != null) return;
_hotKey = new HotKey(ModifierKeys.Control | ModifierKeys.Shift, Key.V, Current.MainWindow);
_hotKey.HotKeyPressed += OnHotKeyPressed;
}
private void UnregisterHotKeys()
{
if (_hotKey == null) return;
_hotKey.HotKeyPressed -= OnHotKeyPressed;
_hotKey.Dispose();
}
private void OnHotKeyPressed(HotKey hotKey)
{
// Do whatever you want to do here
}
}
Related Topics
Nunit VS. Visual Studio 2008's Test Projects for Unit Testing
How to Create a Product Key for My C# Application
How to Set Up HTML/Email Templates with ASP.NET
How to Wait for Async Method to Complete
How Do C# Events Work Behind the Scenes
How to Provide Custom Cast Support for My Class
Illustrating Usage of the Volatile Keyword in C#
What's the Difference Between Iequatable and Just Overriding Object.Equals()
Why Use Try {} Finally {} with an Empty Try Block
What Is the Point of Lookup<Tkey, Telement>
Example Using Hyperlink in Wpf
How to Find Fqdn of Local MAChine in C#/.Net
How Would You Make a Unique Filename by Adding a Number
How Abstraction and Encapsulation Differ
String Interning in .Net Framework - What Are the Benefits and When to Use Interning
Is There Any Way in C# to Override a Class Method with an Extension Method
Win32_Processor::Is Processorid Unique for All Computers
Is It Appropriate to Extend Control to Provide Consistently Safe Invoke/Begininvoke Functionality