I would like to maintain num-lock ON as long as my application is running, so that if the user un-toggles num-lock, it will immediately be toggled back on. What's the simplest way to achieve that in C#?
To clarify, while my application is running I "own" the user's machine, so in my specific case there will not be a need for the user to un-toggle num-lock (that does not mean I have focus at all times).
Thanks
You can do it with a few P/Invoke calls. Check out this page
Enable Form.KeyPreview on your form, add a reference to Microsoft.VisualBasic (or you can use the native API directly to poll the state of the num lock key).
public static class NativeMethods
{
public const byte VK_NUMLOCK = 0x90;
public const uint KEYEVENTF_EXTENDEDKEY = 1;
public const int KEYEVENTF_KEYUP = 0x2;
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
public static void SimulateKeyPress(byte keyCode)
{
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
public partial class Form1 : Form
{
private bool protectKeys; // To protect from inifite keypress chain reactions
public Form1()
{
InitializeComponent();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (protectKeys)
return;
if (e.KeyCode == Keys.NumLock &&
!(new Microsoft.VisualBasic.Devices.Keyboard().NumLock))
{
protectKeys = true;
NativeMethods.SimulateKeyPress(NativeMethods.VK_NUMLOCK);
protectKeys = false;
}
}
}
You need to add a low level keyboard hook to do this. Stephen Toub wrote a tutorial on his blog on setting this up.
Your keyboard hook can check the status of VK_NUMLOCK. For a VB example see here.
Related
I've been searching for a while and there are mostly results in C++ or other languages, and not C#. Things I've seen:
keybd_event() // A c++ method that theoretically can be included with a DLL import, but hasn't worked in testing
System.Windows.Forms.SendKeys.Send("{NUMLOCK}"}; // Forms namespace doesn't exist in Windows
Currently, I have code that executes every second or so to watch the state of numlock and update a graphic in my form accordingly. If a bool toggle is set, I also want it to force NumLock on:
internal partial class Interop
{
public static int VK_NUMLOCK = 0x90;
public static int VK_SCROLL = 0x91;
public static int VK_CAPITAL = 0x14;
public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.
[DllImport("User32.dll", SetLastError = true)]
public static extern void keybd_event(
byte bVk,
byte bScan,
int dwFlags,
IntPtr dwExtraInfo);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetKeyState(int nVirtKey);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetAsyncKeyState(int vKey);
}
private void watcher(object source, ElapsedEventArgs e)
{
bool NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
if (!NumLock && fixers.watchNumL)
{
// Force NumLock back on
// Simulate a key press
Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | 0,IntPtr.Zero);
// Simulate a key release
Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP, IntPtr.Zero);
NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
}
if (NumLock)
{
this.Dispatcher.Invoke(() =>
{
fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(#"/graphics/num_lock_on.png", UriKind.Relative));
StatusBox.Text = "Num Lock ON";
});
}
else {
this.Dispatcher.Invoke(() =>
{
fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(#"/graphics/num_lock_off.png", UriKind.Relative));
StatusBox.Text = "Num Lock OFF";
});
}
}
public MainWindow()
{
// Start the watcher
System.Timers.Timer myTimer = new System.Timers.Timer();
// Tell the timer what to do when it elapses
myTimer.Elapsed += new ElapsedEventHandler(watcher);
// Set it to go off every second
myTimer.Interval = 1000;
// And start it
myTimer.Enabled = true;
}
Here is a class (with a library) that can do this for you. the library does much more, so it's maybe a bit overkill to use just for this. The approach uses the keybd_event function using pinvoke:
// Simulate a key press
Interop.keybd_event((byte)virtualKey,
0x45,
Interop.KEYEVENTF_EXTENDEDKEY | 0,
IntPtr.Zero);
// Simulate a key release
Interop.keybd_event((byte)virtualKey,
0x45,
Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP,
IntPtr.Zero);
Pressing and releasing the button changes the state of the LED. virtualKey is one of the VK_ constants.
Here are the declarations:
internal partial class Interop
{
public static int VK_NUMLOCK = 0x90;
public static int VK_SCROLL = 0x91;
public static int VK_CAPITAL = 0x14;
public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.
[DllImport("User32.dll", SetLastError = true)]
public static extern void keybd_event(
byte bVk,
byte bScan,
int dwFlags,
IntPtr dwExtraInfo);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetKeyState(int nVirtKey);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetAsyncKeyState(int vKey);
}
I'm programming kind of security application
it records the keyboard keys ..
i want to hide the application and then show it when the user presses a key
i tried the following
Hide Button :
private void button4_Click(object sender, EventArgs e)
{
ShowInTaskbar = false;
this.Visible = false;
this.TopMost = true;
}
and key event
private void KeyEvent(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Control && e.Modifiers== Keys.F12) {
this.Visible = true;
}
}
and of course the form load
private void Form2_Load(object sender, EventArgs e)
{
KeyPreview = true;
this.KeyUp+=new System.Windows.Forms.KeyEventHandler(KeyEvent);
}
But no matter how many times i press the keys .. i wont show !!
What should i do ??
As others have stated, your app won't have input focus and won't be listening to key presses.
You need to hook into RegisterHotKey in user32.dll, e.g:
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
Example:
public class GlobalHotKey
{
private int modifier;
private int key;
private IntPtr hWnd;
private int id;
public GlobalHotKey(int modifier, Keys key, Form form)
{
this.modifier = modifier;
this.key = (int)key;
this.hWnd = form.Handle;
id = this.GetHashCode();
}
public bool Register()
{
return RegisterHotKey(hWnd, id, modifier, key);
}
public bool Unregister()
{
return UnregisterHotKey(hWnd, id);
}
public override int GetHashCode()
{
return modifier ^ key ^ hWnd.ToInt32();
}
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
}
public static class Constants
{
public const int NOMOD = 0x0000;
public const int ALT = 0x0001;
public const int CTRL = 0x0002;
public const int SHIFT = 0x0004;
public const int WIN = 0x0008;
public const int WM_HOTKEY_MSG_ID = 0x0312;
}
Usage:
private GlobalHotKey globalHotKey;
// Registering your hotkeys
private void Form2_Load(object sender, EventArgs e)
{
globalHotKey = new HotKeys.GlobalHotKey(Constants.CTRL, Keys.F12, this);
bool registered = globalHotKey.Register();
// Handle instances where the hotkey failed to register
if(!registered)
{
MessageBox.Show("Hotkey failed to register");
}
}
// Listen for messages matching your hotkeys
protected override void WndProc(ref Message m)
{
if (m.Msg == HotKeys.Constants.WM_HOTKEY_MSG_ID)
{
HandleHotkey();
}
base.WndProc(ref m);
}
// Do something when the hotkey is pressed
private void HandleHotkey()
{
if(this.Visible)
this.Hide();
else
this.Show();
}
You'll want to make sure you unregister the key when the app closes too:
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
if (!globalHotKey.Unregister())
{
Application.Exit();
}
}
This is because your application does not have input focus and therefore will not be picking up the key presses. You need to hook into lower-level OS to get keyboard input when your application does not have focus.
A similar question was posted and answered here: Global keyboard capture in C# application
Read documentation? Aan application only gets the key presses for its windows. Logically this means a hidden window can not get key presses.
You hook into the forms handler so you only see the presses on your forms, which are invisible so never can have the focus to get key presses.
There are HOOKS you can use in Windows to hook into the general processing, but beare side effects (i.e. other programs also reacting or you blocking keys).
I suggest looking into this:
Processing global mouse and keyboard hooks from C#
In essense, what you want lies outside of .net capabilities, and must be implemented via Windows API, and, consequently, using a native language. However when you recieve input through winAPI, you can pass it to your application, using project i linked to as a guide.
I'm working on a program, who need to detect when the user press the keyboard or use his mouse, even if the program is minimized or not focused.
I think I have to use the windows API, keybd_event (user32), but I don't know how to use the "listener" of this event. I have something like that:
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags,UIntPtr dwExtraInfo);
void PressKey(byte keyCode)
{
//My code here
}
I did some research, but it's the first time I have to use DllImport, so I don't know how to continue ...
Thanks
(Ps:Sorry about my bad English, this is not my native language :) )
(PPs: I've read all of your answers, but it takes a while to read every link, so I'll work on it tonight, but I think I will find the answer. Anyway, thanks for the links everybody ;) )
Edit: So I just finished my code and it's work :) It looks something like:
[DllImport("user32.dll")]
public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);
public struct tagLASTINPUTINFO
{
public uint cbSize;
public Int32 dwTime;
}
private void timerTemps_Inactif_Tick(object sender, EventArgs e)
{
tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
Int32 IdleTime;
LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
LastInput.dwTime = 0;
if (GetLastInputInfo(ref LastInput))
{
IdleTime = System.Environment.TickCount - LastInput.dwTime;
if (IdleTime > 10000)
{
//My code here
}
}
}
Thanks for the help guys ;)
You will need to hook into Windows OS with SetWindowsHookEx function. You should read the article Keyloggers: How they work and how to detect them posted by SecureList to get a understanding ofthe process.
I have always got a good performance by using RegisterHotKey/UnregisterHotKey functions. Sample code:
[DllImport("User32")]
public static extern bool RegisterHotKey(
IntPtr hWnd,
int id,
int fsModifiers,
int vk
);
[DllImport("User32")]
public static extern bool UnregisterHotKey(
IntPtr hWnd,
int id
);
public const int MOD_SHIFT = 0x4;
public const int MOD_CONTROL = 0x2;
public const int MOD_ALT = 0x1;
public const int WM_HOTKEY = 0x312;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_HOTKEY && m.WParam == (IntPtr)0)
{
IntPtr lParamCTRLA = (IntPtr)4259842;
IntPtr lParamB = (IntPtr)4325376;
if (m.LParam == lParamCTRLA)
{
MessageBox.Show("CTRL+A was pressed");
}
else if (m.LParam == lParamB)
{
MessageBox.Show("B was pressed");
}
}
base.WndProc(ref m);
}
private void Form1_Load(object sender, EventArgs e)
{
this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
RegisterHotKey(this.Handle, 0, MOD_CONTROL, (int)Keys.A);
RegisterHotKey(this.Handle, 0, 0, (int)Keys.B);
}
private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 0);
}
You can "register" as many keys (or combination of keys) as you want by emulating the shown structure. All the registered keys will get inside the condition if (m.Msg == WM_HOTKEY && m.WParam == (IntPtr)0); if they are pressed at all (independently upon the program currently being selected). The easiest way to know the specific key/combination being pressed is relying on m.LParam (I got the two values I am including after a quick test with the given keys). You can do a quick research to find out a list of LParam or further constant modifiers (wheel of the mouse, for example).
The final code:
[DllImport("user32.dll")]
public static extern Boolean GetLastInputInfo(ref tagLASTINPUTINFO plii);
public struct tagLASTINPUTINFO
{
public uint cbSize;
public Int32 dwTime;
}
private void timerTemps_Inactif_Tick(object sender, EventArgs e)
{
tagLASTINPUTINFO LastInput = new tagLASTINPUTINFO();
Int32 IdleTime;
LastInput.cbSize = (uint)Marshal.SizeOf(LastInput);
LastInput.dwTime = 0;
if (GetLastInputInfo(ref LastInput))
{
IdleTime = System.Environment.TickCount - LastInput.dwTime;
if (IdleTime > 10000)
{
//My code here
}
}
}
My webbrowser:
XAML:
//...
xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
//...
<my:WindowsFormsHost Name="windowsFormsHost"/>
Code behind C#:
System.Windows.Forms.WebBrowser Browser = new System.Windows.Forms.WebBrowser();
windowsFormsHost.Child = Browser;
My question is how to disable all audio output.
I found this:
C#:
private const int Feature = 21; //FEATURE_DISABLE_NAVIGATION_SOUNDS
private const int SetFeatureOnProcess = 0x00000002;
[DllImport("urlmon.dll")]
[PreserveSig]
[return: MarshalAs(UnmanagedType.Error)]
static extern int CoInternetSetFeatureEnabled(int featureEntry,
[MarshalAs(UnmanagedType.U4)] int dwFlags,
bool fEnable);
Its fine, but this code disable only "click" sound, so its kind of useless in this case.
I just want from my application 100% mute, no sounds at all.
I've read that in this webbrowser it need to be done through Windows Sounds, but I cant really bielieve that I cant do this in code.
Here is how you can do it with ease. Not specific to WebBrowser though, but does what you requested: I just want from my application 100% mute, no sounds at all.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WinformsWB
{
public partial class Form1 : Form
{
[DllImport("winmm.dll")]
public static extern int waveOutGetVolume(IntPtr h, out uint dwVolume);
[DllImport("winmm.dll")]
public static extern int waveOutSetVolume(IntPtr h, uint dwVolume);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// save the current volume
uint _savedVolume;
waveOutGetVolume(IntPtr.Zero, out _savedVolume);
this.FormClosing += delegate
{
// restore the volume upon exit
waveOutSetVolume(IntPtr.Zero, _savedVolume);
};
// mute
waveOutSetVolume(IntPtr.Zero, 0);
this.webBrowser1.Navigate("http://youtube.com");
}
}
}
You can try as well to use DISPID_AMBIENT_DLCONTROL
DLCTL_DLIMAGES, DLCTL_VIDEOS, and DLCTL_BGSOUNDS: Images, videos, and background sounds will be downloaded from the server and displayed or played if these flags are set. They will not be downloaded and displayed if the flags are not set.
I'm building an application in C# using WPF. How can I bind to some keys?
Also, how can I bind to the Windows key?
This is a full working solution, hope it helps...
Usage:
_hotKey = new HotKey(Key.F9, KeyModifier.Shift | KeyModifier.Win, OnHotKeyHandler);
...
private void OnHotKeyHandler(HotKey hotKey)
{
SystemHelper.SetScreenSaverRunning();
}
Class:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Mime;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
namespace UnManaged
{
public class HotKey : IDisposable
{
private static Dictionary<int, HotKey> _dictHotKeyToCalBackProc;
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, UInt32 fsModifiers, UInt32 vlc);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public const int WmHotKey = 0x0312;
private bool _disposed = false;
public Key Key { get; private set; }
public KeyModifier KeyModifiers { get; private set; }
public Action<HotKey> Action { get; private set; }
public int Id { get; set; }
// ******************************************************************
public HotKey(Key k, KeyModifier keyModifiers, Action<HotKey> action, bool register = true)
{
Key = k;
KeyModifiers = keyModifiers;
Action = action;
if (register)
{
Register();
}
}
// ******************************************************************
public bool Register()
{
int virtualKeyCode = KeyInterop.VirtualKeyFromKey(Key);
Id = virtualKeyCode + ((int)KeyModifiers * 0x10000);
bool result = RegisterHotKey(IntPtr.Zero, Id, (UInt32)KeyModifiers, (UInt32)virtualKeyCode);
if (_dictHotKeyToCalBackProc == null)
{
_dictHotKeyToCalBackProc = new Dictionary<int, HotKey>();
ComponentDispatcher.ThreadFilterMessage += new ThreadMessageEventHandler(ComponentDispatcherThreadFilterMessage);
}
_dictHotKeyToCalBackProc.Add(Id, this);
Debug.Print(result.ToString() + ", " + Id + ", " + virtualKeyCode);
return result;
}
// ******************************************************************
public void Unregister()
{
HotKey hotKey;
if (_dictHotKeyToCalBackProc.TryGetValue(Id, out hotKey))
{
UnregisterHotKey(IntPtr.Zero, Id);
}
}
// ******************************************************************
private static void ComponentDispatcherThreadFilterMessage(ref MSG msg, ref bool handled)
{
if (!handled)
{
if (msg.message == WmHotKey)
{
HotKey hotKey;
if (_dictHotKeyToCalBackProc.TryGetValue((int)msg.wParam, out hotKey))
{
if (hotKey.Action != null)
{
hotKey.Action.Invoke(hotKey);
}
handled = true;
}
}
}
}
// ******************************************************************
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// ******************************************************************
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be _disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be _disposed.
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this._disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
Unregister();
}
// Note disposing has been done.
_disposed = true;
}
}
}
// ******************************************************************
[Flags]
public enum KeyModifier
{
None = 0x0000,
Alt = 0x0001,
Ctrl = 0x0002,
NoRepeat = 0x4000,
Shift = 0x0004,
Win = 0x0008
}
// ******************************************************************
}
I'm not sure of what you mean by "global" here, but here it goes (I'm assuming you mean a command at the application level, for example, Save All that can be triggered from anywhere by Ctrl + Shift + S.)
You find the global UIElement of your choice, for example, the top level window which is the parent of all the controls where you need this binding. Due to "bubbling" of WPF events, events at child elements will bubble all the way up to the root of the control tree.
Now, first you need
to bind the Key-Combo with a Command using an InputBinding like this
you can then hookup the command to your handler (e.g. code that gets called by SaveAll) via a CommandBinding.
For the Windows Key, you use the right Key enumerated member, Key.LWin or Key.RWin
public WindowMain()
{
InitializeComponent();
// Bind Key
var ib = new InputBinding(
MyAppCommands.SaveAll,
new KeyGesture(Key.S, ModifierKeys.Shift | ModifierKeys.Control));
this.InputBindings.Add(ib);
// Bind handler
var cb = new CommandBinding( MyAppCommands.SaveAll);
cb.Executed += new ExecutedRoutedEventHandler( HandlerThatSavesEverthing );
this.CommandBindings.Add (cb );
}
private void HandlerThatSavesEverthing (object obSender, ExecutedRoutedEventArgs e)
{
// Do the Save All thing here.
}
Registering OS level shortcuts is hardly ever a good thing: users don't want you to mess with their OS.
That said, there is a much simpler and user friendly way of doing this in WPF, if you're ok with the hotkey working within the application only (i.e as long as your WPF app has the focus):
In App.xaml.cs :
protected override void OnStartup(StartupEventArgs e)
{
EventManager.RegisterClassHandler(typeof(Window), Window.PreviewKeyUpEvent, new KeyEventHandler(OnWindowKeyUp));
}
private void OnWindowKeyUp(object source, KeyEventArgs e))
{
//Do whatever you like with e.Key and Keyboard.Modifiers
}
It's that simple
If you're going to mix Win32 and WPF, here's how I did it:
using System;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows.Media;
using System.Threading;
using System.Windows;
using System.Windows.Input;
namespace GlobalKeyboardHook
{
public class KeyboardHandler : IDisposable
{
public const int WM_HOTKEY = 0x0312;
public const int VIRTUALKEYCODE_FOR_CAPS_LOCK = 0x14;
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private readonly Window _mainWindow;
WindowInteropHelper _host;
public KeyboardHandler(Window mainWindow)
{
_mainWindow = mainWindow;
_host = new WindowInteropHelper(_mainWindow);
SetupHotKey(_host.Handle);
ComponentDispatcher.ThreadPreprocessMessage += ComponentDispatcher_ThreadPreprocessMessage;
}
void ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, ref bool handled)
{
if (msg.message == WM_HOTKEY)
{
//Handle hot key kere
}
}
private void SetupHotKey(IntPtr handle)
{
RegisterHotKey(handle, GetType().GetHashCode(), 0, VIRTUALKEYCODE_FOR_CAPS_LOCK);
}
public void Dispose()
{
UnregisterHotKey(_host.Handle, GetType().GetHashCode());
}
}
}
You can get the virtual-key code for the hotkey you want to register here: http://msdn.microsoft.com/en-us/library/ms927178.aspx
There may be a better way, but this is what I've got so far.
Cheers!
This is similar to the answers already given, but I find it a bit cleaner:
using System;
using System.Windows.Forms;
namespace GlobalHotkeyExampleForm
{
public partial class ExampleForm : Form
{
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
enum KeyModifier
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
WinKey = 8
}
public ExampleForm()
{
InitializeComponent();
int id = 0; // The id of the hotkey.
RegisterHotKey(this.Handle, id, (int)KeyModifier.Shift, Keys.A.GetHashCode()); // Register Shift + A as global hotkey.
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0x0312)
{
/* Note that the three lines below are not needed if you only want to register one hotkey.
* The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF); // The key of the hotkey that was pressed.
KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF); // The modifier of the hotkey that was pressed.
int id = m.WParam.ToInt32(); // The id of the hotkey that was pressed.
MessageBox.Show("Hotkey has been pressed!");
// do something
}
}
private void ExampleForm_FormClosing(object sender, FormClosingEventArgs e)
{
UnregisterHotKey(this.Handle, 0); // Unregister hotkey with id 0 before closing the form. You might want to call this more than once with different id values if you are planning to register more than one hotkey.
}
}
}
I've found it on fluxbytes.com.
With the NHotKey package, you can make your hotkey global:
https://github.com/thomaslevesque/NHotkey
https://thomaslevesque.com/2014/02/05/wpf-declare-global-hotkeys-in-xaml-with-nhotkey/ (use web.archive.org if the link is broken)
In short, for XAML, all you need to do is to replace
<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}" />
by
<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}"
HotkeyManager.RegisterGlobalHotkey="True" />
I'm not sure about WPF, but this may help. I used the solution described in RegisterHotKey (user32) (modified to my needs of course) for a C# Windows Forms application to assign a CTRL-KEY combination within Windows to bring up a C# form, and it worked beautifully (even on Windows Vista). I hope it helps and good luck!
I've found the Global Hotkeys in WPF project on codeproject.com which does the job for me. It's relatively recent, does not need a reference to System.Windows.Forms and works "globally" in terms of reacting to the hotkey being pressed even if "your" application is not the active window.
Baboon's solution works best because you may have multiple windows. I did tweak it so it uses the PreviewKeyDownEvent instead of the PreviewKeyUpEvent in order to handle repetition in keystrokes.
I would advise against OS-level registration unless you are writing something like a snipping tool or an audio recording app as it will let you access functionality when the window is not focused.
Although RegisterHotKey is sometimes precisely what you want, in most cases you probably do not want to use system-wide hotkeys. I ended up using code like the following:
using System.Windows;
using System.Windows.Interop;
namespace WpfApp
{
public partial class MainWindow : Window
{
const int WM_KEYUP = 0x0101;
const int VK_RETURN = 0x0D;
const int VK_LEFT = 0x25;
public MainWindow()
{
this.InitializeComponent();
ComponentDispatcher.ThreadPreprocessMessage +=
ComponentDispatcher_ThreadPreprocessMessage;
}
void ComponentDispatcher_ThreadPreprocessMessage(
ref MSG msg, ref bool handled)
{
if (msg.message == WM_KEYUP)
{
if ((int)msg.wParam == VK_RETURN)
MessageBox.Show("RETURN was pressed");
if ((int)msg.wParam == VK_LEFT)
MessageBox.Show("LEFT was pressed");
}
}
}
}
RegisterHotKey() suggested by John could work - the only catch is that it requires an HWND (using PresentationSource.FromVisual(), and casting the result to an HwndSource).
However, you'll also need to respond to the WM_HOTKEY message - I'm not sure if there is a way to get access to the WndProc of a WPF window or not (which can be done for Windows Forms windows).