在C#应用程序中接收操作系统级别的按键事件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在C#应用程序中接收操作系统级别的按键事件相关的知识,希望对你有一定的参考价值。
我不知道这个问题有更好的标题,但我会说明我的问题。
我正在开发类似MP3播放器的应用程序,它使用多媒体键来播放/暂停,停止歌曲,我实际上使它工作但是FormApplication必须在顶部[聚焦]
protected override void WndProc(ref Message msg)
{
if (msg.Msg == 0x319) // WM_APPCOMMAND message
{
// extract cmd from LPARAM (as GET_APPCOMMAND_LPARAM macro does)
int cmd = (int)((uint)msg.LParam >> 16 & ~0xf000);
switch (cmd)
{
case 13: // APPCOMMAND_MEDIA_STOP constant
MessageBox.Show("Stop");
break;
case 14: // APPCOMMAND_MEDIA_PLAY_PAUSE
MessageBox.Show("Play/Pause");
break;
case 11: // APPCOMMAND_MEDIA_NEXTTRACK
MessageBox.Show("Next");
break;
case 12: // APPCOMMAND_MEDIA_PREVIOUSTRACK
MessageBox.Show("Previous");
break;
default:
break;
}
}
base.WndProc(ref msg);
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
Message m = new Message();
m.Msg = e.KeyChar;
WndProc(ref m);
}
所以我需要做的是:即使程序在后台并且不在顶部或聚焦,使多媒体键工作,就像winamp和Windows Media Player的工作方式一样。
我在互联网上搜索了很多,但大多数给了我类似于我正在使用的方式。
非常感谢您的帮助。
答案
您需要一个OS级别的键盘钩子。例如user32.dll
SetWindowsHookEx
通过P/Invoke
。您可以在下面找到一个示例,但您必须根据自己的需要进行定制。
注意:这里的Dispatcher
是WPF调度程序,因此可以引发RawKeyEventArgs
。
KeyboardListener.cs
/// <summary>
/// Listens keyboard globally.
///
/// <remarks>Uses WH_KEYBOARD_LL.</remarks>
/// </summary>
public class KeyboardListener : IDisposable
{
/// <summary>
/// Creates global keyboard listener.
/// </summary>
public KeyboardListener(Dispatcher dispatcher)
{
// Dispatcher thread handling the KeyDown/KeyUp events.
_dispatcher = dispatcher;
// We have to store the LowLevelKeyboardProc, so that it is not garbage collected runtime
_hookedLowLevelKeyboardProc = LowLevelKeyboardProc;
// Set the hook
_hookId = InterceptKeys.SetHook(_hookedLowLevelKeyboardProc);
// Assign the asynchronous callback event
_hookedKeyboardCallbackAsync = new KeyboardCallbackAsync(KeyboardListener_KeyboardCallbackAsync);
}
private readonly Dispatcher _dispatcher;
/// <summary>
/// Destroys global keyboard listener.
/// </summary>
~KeyboardListener()
{
Dispose();
}
/// <summary>
/// Fired when any of the keys is pressed down.
/// </summary>
public event EventHandler<RawKeyEventArgs> KeyDown;
/// <summary>
/// Fired when any of the keys is released.
/// </summary>
public event EventHandler<RawKeyEventArgs> KeyUp;
#region Inner workings
/// <summary>
/// Hook ID
/// </summary>
private readonly IntPtr _hookId = IntPtr.Zero;
/// <summary>
/// Asynchronous callback hook.
/// </summary>
/// <param name="character">Character</param>
/// <param name="keyEvent">Keyboard event</param>
/// <param name="vkCode">VKCode</param>
private delegate void KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode, string character);
/// <summary>
/// Actual callback hook.
///
/// <remarks>Calls asynchronously the asyncCallback.</remarks>
/// </summary>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
[MethodImpl(MethodImplOptions.NoInlining)]
private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
if (wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYDOWN ||
wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYUP ||
wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYDOWN ||
wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYUP)
{
// Captures the character(s) pressed only on WM_KEYDOWN
string chars = InterceptKeys.VKCodeToString((uint)Marshal.ReadInt32(lParam),
(wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYDOWN ||
wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYDOWN));
_hookedKeyboardCallbackAsync.BeginInvoke((InterceptKeys.KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), chars, null, null);
}
return InterceptKeys.CallNextHookEx(_hookId, nCode, wParam, lParam);
}
/// <summary>
/// Event to be invoked asynchronously (BeginInvoke) each time key is pressed.
/// </summary>
private readonly KeyboardCallbackAsync _hookedKeyboardCallbackAsync;
/// <summary>
/// Contains the hooked callback in runtime.
/// </summary>
private readonly InterceptKeys.LowLevelKeyboardProc _hookedLowLevelKeyboardProc;
/// <summary>
/// HookCallbackAsync procedure that calls accordingly the KeyDown or KeyUp events.
/// </summary>
/// <param name="keyEvent">Keyboard event</param>
/// <param name="vkCode">VKCode</param>
/// <param name="character">Character as string.</param>
void KeyboardListener_KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode, string character)
{
switch (keyEvent)
{
// KeyDown events
case InterceptKeys.KeyEvent.WM_KEYDOWN:
if (KeyDown != null)
_dispatcher.BeginInvoke(new EventHandler<RawKeyEventArgs>(KeyDown), this, new RawKeyEventArgs(vkCode, false, character));
break;
case InterceptKeys.KeyEvent.WM_SYSKEYDOWN:
if (KeyDown != null)
_dispatcher.BeginInvoke(new EventHandler<RawKeyEventArgs>(KeyDown), this, new RawKeyEventArgs(vkCode, true, character));
break;
// KeyUp events
case InterceptKeys.KeyEvent.WM_KEYUP:
if (KeyUp != null)
_dispatcher.BeginInvoke(new EventHandler<RawKeyEventArgs>(KeyUp), this, new RawKeyEventArgs(vkCode, false, character));
break;
case InterceptKeys.KeyEvent.WM_SYSKEYUP:
if (KeyUp != null)
_dispatcher.BeginInvoke(new EventHandler<RawKeyEventArgs>(KeyUp), this, new RawKeyEventArgs(vkCode, true, character));
break;
default:
break;
}
}
#endregion
#region IDisposable Members
/// <summary>
/// Disposes the hook.
/// <remarks>This call is required as it calls the UnhookWindowsHookEx.</remarks>
/// </summary>
public void Dispose()
{
InterceptKeys.UnhookWindowsHookEx(_hookId);
}
#endregion
}
InterceptKeys.cs
/// <summary>
/// Winapi Key interception helper class.
/// </summary>
internal static class InterceptKeys
{
public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);
private const int WH_KEYBOARD_LL = 13;
/// <summary>
/// Key event
/// </summary>
public enum KeyEvent : int
{
/// <summary>
/// Key down
/// </summary>
WM_KEYDOWN = 256,
/// <summary>
/// Key up
/// </summary>
WM_KEYUP = 257,
/// <summary>
/// System key up
/// </summary>
WM_SYSKEYUP = 261,
/// <summary>
/// System key down
/// </summary>
WM_SYSKEYDOWN = 260
}
public 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);
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idH以上是关于在C#应用程序中接收操作系统级别的按键事件的主要内容,如果未能解决你的问题,请参考以下文章