C# 当Visual Studio具有焦点(或任何以管理员身份运行的应用程序)时,keybd_事件以及PostMessage win32不工作
这是一个程序,我已经使用了许多改变,从旧的xp的一天 这是一个cmd行程序,它将改变媒体应用程序(Spotify、vlc、mediaPlayer)中的曲目,就像带有下一个/上一个曲目按钮的键盘一样 目前我使用的是微软自然键盘,它没有这些按钮,但有可编程的按键来执行这个程序 除了VisualStudio2012/2013具有焦点(Windows 7)(没有尝试过其他版本)并且它在Sql management Studio中工作外,所有这些都可以工作C# 当Visual Studio具有焦点(或任何以管理员身份运行的应用程序)时,keybd_事件以及PostMessage win32不工作,c#,interop,keyboard-shortcuts,C#,Interop,Keyboard Shortcuts,这是一个程序,我已经使用了许多改变,从旧的xp的一天 这是一个cmd行程序,它将改变媒体应用程序(Spotify、vlc、mediaPlayer)中的曲目,就像带有下一个/上一个曲目按钮的键盘一样 目前我使用的是微软自然键盘,它没有这些按钮,但有可编程的按键来执行这个程序 除了VisualStudio2012/2013具有焦点(Windows 7)(没有尝试过其他版本)并且它在Sql management Studio中工作外,所有这些都可以工作 using System; using Syst
using System;
using System.Runtime.InteropServices;
namespace NxtTrack
{
class Program
{
[DllImport("user32.dll")]
private static extern bool PostMessage(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern void keybd_event(byte vkCode, byte scanCode, int flags, IntPtr extraInfo);
enum TrackMove
{
Previous,Next
}
static void Main(string[] args)
{
TrackMove trackMove;
try
{
if(args[0].ToLower().Contains("previous"))
trackMove = TrackMove.Previous;
else if(args[0].ToLower().Contains("next"))
trackMove = TrackMove.Next;
else
{
throw new Exception("wrong param");
}
}
catch
{
Console.WriteLine("Params needed: Next or Previous");
return;
}
TrackKeys(trackMove);
}
private static void TrackKeys(TrackMove trackMove)
{
//http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx
byte msg = trackMove == TrackMove.Previous ? (byte)0xB1 : (byte)0xB0;
keybd_event(msg, 0x45, 0, IntPtr.Zero);
}
}
}
问题是VS在发送消息时有焦点,您只能将焦点放在正确的应用程序上
若要解决此问题,请在调用keybd_事件之前放置一个
线程。Sleep
,在睡眠之前放置F5,并在此时将焦点更改到正确的位置。问题是在发送消息时VS具有焦点,您只能将其与正确应用程序上的焦点一起工作
要解决此问题,请在调用keybd_事件之前放置一个
线程。Sleep
,在睡眠之前放置F5,并在此时将焦点更改到正确的位置。这些是VK_MEDIA_NEXT_TRACK和VK_MEDIA_PREV_TRACK虚拟键。对它们的处理非常复杂:
- 任何拥有前台窗口的程序都将在调用GetMessage()时从其消息队列中检索他的击键
- 该程序消息循环中的TranslateMessage()调用将击键转换为APPCOMMAND_MEDIA_NEXTTRACK或APPCOMMAND_MEDIA_PREVIOUSTRACK,并将其发送到具有焦点的子窗口
- 子窗口将不使用它,并将消息传递给DefWindowProc()
- 将消息传递给子窗口的父窗口。这会在嵌套子窗口时重复,最终到达顶层窗口
- 当它调用DefWindowProc时,Windows会调用一个shell钩子来触发任何程序中的回调,该程序为WH_shell钩子HSHELL_APPCOMMAND通知调用了setWindowshookx()。像Windows Media Player这样的程序将使用该功能
- 如果没有钩子拦截它,它最终将作为最后一个钩子出现在Explorer中,最后一个钩子将执行该操作
AppCommand.Send(AppCommands.MediaNext);
我把你能发出的所有命令都放进去了。我提供了一个Cleanup()方法来释放资源,不需要调用它。该代码与.NET版本2.0到4.5.1兼容
using System;
using System.Threading;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public enum AppCommands {
BrowserBack = 1,
BrowserForward = 2,
BrowserRefresh = 3,
BrowserStop = 4,
BrowserSearch = 5,
BrowserFavorite = 6,
BrowserHome = 7,
VolumeMute = 8,
VolumeDown = 9,
VolumeUp = 10,
MediaNext = 11,
MediaPrevious = 12,
MediaStop = 13,
MediaPlayPause = 14,
LaunchMail = 15,
LaunchMediaSelect = 16,
LaunchApp1 = 17,
LaunchApp2 = 18,
BassDown = 19,
BassBoost = 20,
BassUp = 21,
TrebleUp = 22,
TrebleDown = 23,
MicrophoneMute = 24,
MicrophoneVolumeUp = 25,
MicrophoneVolumeDown = 26,
Help = 27,
Find = 28,
New = 29,
Open = 30,
Close = 31,
Save = 32,
Print = 33,
Undo = 34,
Redo = 35,
Copy = 36,
Cut = 37,
Paste = 38,
ReplyToMail = 39,
ForwardMail = 40,
SendMail = 41,
SpellCheck = 42,
Dictate = 43,
MicrophoneOnOff = 44,
CorrectionList = 45,
MediaPlay = 46,
MediaPause = 47,
MediaRecord = 48,
MediaFastForward = 49,
MediaRewind = 50,
MediaChannelUp = 51,
MediaChannelDown = 52,
Delete = 53,
Flip3D = 54
}
public static class AppCommand {
public static void Send(AppCommands cmd) {
if (frm == null) Initialize();
frm.Invoke(new MethodInvoker(() => SendMessage(frm.Handle, WM_APPCOMMAND, frm.Handle, (IntPtr)((int)cmd << 16))));
}
private static void Initialize() {
// Run the message loop on another thread so we're compatible with a console mode app
var t = new Thread(() => {
frm = new Form();
var dummy = frm.Handle;
frm.BeginInvoke(new MethodInvoker(() => mre.Set()));
Application.Run();
});
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
mre.WaitOne();
}
public static void Cleanup() {
if (frm != null) {
frm.BeginInvoke(new MethodInvoker(() => {
frm.Close();
Application.ExitThread();
mre.Set();
}));
mre.WaitOne();
frm = null;
}
}
private static ManualResetEvent mre = new ManualResetEvent(false);
private static Form frm;
// Pinvoke
private const int WM_APPCOMMAND = 0x319;
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
使用系统;
使用系统线程;
使用System.Windows.Forms;
使用System.Runtime.InteropServices;
公共枚举AppCommands{
BrowserBack=1,
BrowserForward=2,
BrowserRefresh=3,
BrowserStop=4,
BrowserSearch=5,
BrowserFavorite=6,
BrowserHome=7,
体积=8,
体积向下=9,
体积p=10,
MediaNext=11,
MediaPrevious=12,
MediaStop=13,
MediaPlayPause=14,
LaunchMail=15,
LaunchMediaSelect=16,
LaunchApp1=17,
LaunchApp2=18,
BassDown=19,
BassBoost=20,
BassUp=21,
TrebleUp=22,
三倍降=23,
麦克风静音=24,
麦克风音量p=25,
麦克风音量向下=26,
帮助=27,
Find=28,
新=29,
开=30,
关闭=31,
Save=32,
打印=33,
撤销=34,
重做=35,
复制=36,
切割=37,
粘贴=38,
ReplyToMail=39,
ForwardMail=40,
SendMail=41,
拼写检查=42,
口述=43,
麦克风断开=44,
更正列表=45,
MediaPlay=46,
MediaPause=47,
MediaRecord=48,
MediaFastForward=49,
MediaRewind=50,
MediaChannelUp=51,
MediaChannelDown=52,
删除=53,
Flip3D=54
}
公共静态类AppCommand{
公共静态无效发送(AppCommands cmd){
如果(frm==null)初始化();
frm.Invoke(new MethodInvoker)(()=>SendMessage(frm.Handle,WM_APPCOMMAND,frm.Handle,(IntPtr)((int)cmd这些是VK_MEDIA_NEXT_TRACK和VK_MEDIA_PREV_TRACK虚拟键。对它们的处理非常复杂:
- 任何拥有前台窗口的程序都将在调用GetMessage()时从其消息队列中检索他的击键
- 该程序消息循环中的TranslateMessage()调用将击键转换为APPCOMMAND_MEDIA_NEXTTRACK或APPCOMMAND_MEDIA_PREVIOUSTRACK,并将其发送到具有焦点的子窗口
- 子窗口将不使用它,并将消息传递给DefWindowProc()
- 它将消息传递给子窗口的父窗口。当子窗口嵌套时,它会重复多次,最终到达顶层窗口
- 当它调用DefWindowProc时,Windows会调用一个shell钩子,以在任何为WH_shell钩子HSHELL_APPCOMMAND调用setWindowshookx()的程序中触发回调