This is a program that I have used with many changes from the old xp day\'s It\'s a cmd line program that will change track in media applications(Spotify,vlc,mediaPlayer) j
The problem is VS has the focus when the message is sent, you can only put this to work with the focus on the correct application.
To work around this put a Thread.Sleep
before the call to keybd_event and F5 before the sleep and change the focus to the correct place in this time.
These are the VK_MEDIA_NEXT_TRACK and VK_MEDIA_PREV_TRACK virtual keys. The processing for them is highly convoluted:
The solution here is to not send a keystroke but move up the previously listed processing chain. It would be nice if it were possible to directly call the shell hook but that feature is not exposed. Next step back is to send the WM_APPCOMMAND message instead.
That requires picking a window to send the message to. That's a difficult these days due to UAC, a feature called UIPI (User Interface Privilege Isolation) prevents a non-elevated program from sending messages to an elevated one. So you can't just use the window in the foreground, it may well be an app that's running with admin privileges. Like Visual Studio, the likely reason why PostMessage and keybd_event() is failing when you tried them.
The trick is to send it to a window that you own. Which you made difficult, you are using a console mode project. That can be worked around. Project + Add Reference, select System.Windows.Forms. Add a new class to your project and paste the code shown below. Replace your keybd_event() call with, say,
AppCommand.Send(AppCommands.MediaNext);
I threw in the whole kit-and-caboodle of all the commands you can send. I provided a Cleanup() method to release resources, it is not necessary to call it. The code is compatible with .NET version 2.0 through 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);
}