Media keys...

  • Thread starter Thread starter hurricane_number_one
  • Start date Start date
H

hurricane_number_one

I want to be able to play/pause/next/back the tracks in whatever media
player app is running. So if iTunes is running, it will receive those
commands, if Windows Media Player is, it will receive those commands,
and so on, just like my multimedia keyboard does. I can't find any way
to do this. I have tried sending:

System.Windows.Forms.Keys.MediaPlayPause,
System.Windows.Forms.Keys.MediaPreviousTrack, ect.

but it didn't do anything. Is there a way to send a key that will
control any open media player app, or do I have to have my app check
all the open apps and use the appropriate method for each app to
control it? Any suggestions? Thanks.
 
I want to be able to play/pause/next/back the tracks in whatever media
player app is running. So if iTunes is running, it will receive those
commands, if Windows Media Player is, it will receive those commands,
and so on, just like my multimedia keyboard does. I can't find any way
to do this. I have tried sending:

System.Windows.Forms.Keys.MediaPlayPause,
System.Windows.Forms.Keys.MediaPreviousTrack, ect.

but it didn't do anything. Is there a way to send a key that will
control any open media player app, or do I have to have my app check
all the open apps and use the appropriate method for each app to
control it? Any suggestions? Thanks.

SendKeys would work if the media keys were supported, but they're not.
Instead, you can call SendInput() yourself by P/Invoking. Here's a short but
complete sample as a console application. It uses .NET 3.5 and LINQ, but
this is just for convenience and you should have no trouble adapting it to
..NET 2.0 if required.

using System;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.ComponentModel;

[StructLayout(LayoutKind.Sequential)]
public struct INPUT {
public int type;
public INPUTUNION inputUnion;
}

[StructLayout(LayoutKind.Explicit)]
public struct INPUTUNION {
// Fields
[FieldOffset(0)]
public HARDWAREINPUT hi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public MOUSEINPUT mi;
}

[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT {
public int uMsg;
public short wParamL;
public short wParamH;
}

[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT {
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT {
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public IntPtr dwExtraInfo;
}

static class NativeMethods {
[DllImport("user32.dll", SetLastError = true)]
public static extern int SendInput(int nInputs, [In] INPUT[] pInputs,
int cbSize);
}

class Program {
static int SendKeys(params Keys[] keys) {
var nativeKeys = keys.Select(
k => new INPUT {
type = 1, inputUnion = new INPUTUNION {
ki = new KEYBDINPUT { wVk = (short) k }
}
}
).ToArray();
int keysSent = NativeMethods.SendInput(nativeKeys.Length, nativeKeys,
Marshal.SizeOf(typeof(INPUT)));
if (keysSent == 0) throw new Win32Exception();
return keysSent;
}

static void Main(string[] args) {
while (true) {
var cki = Console.ReadKey();
switch (cki.KeyChar) {
case 'q': Environment.Exit(0); break;
case ' ': SendKeys(Keys.MediaPlayPause); break;
case 'n': SendKeys(Keys.MediaNextTrack); break;
case 'p': SendKeys(Keys.MediaPreviousTrack); break;
case 's': SendKeys(Keys.MediaStop); break;
}
}
}
}
 
Thanks. I've tried using sendInput before, as well as keybd_event and
neither seems to do anything for the media keys. I'm trying it with
iTunes and Media Player, could it be that those 2 programs ignore
those keys, or should it work?


I want to be able to play/pause/next/back the tracks in whatever media
player app is running. So if iTunes is running, it will receive those
commands, if Windows Media Player is, it will receive those commands,
and so on, just like my multimedia keyboard does. I can't find any way
to do this. I have tried sending:
System.Windows.Forms.Keys.MediaPlayPause,
System.Windows.Forms.Keys.MediaPreviousTrack, ect.
but it didn't do anything. Is there a way to send a key that will
control any open media player app, or do I have to have my app check
all the open apps and use the appropriate method for each app to
control it? Any suggestions? Thanks.

SendKeys would work if the media keys were supported, but they're not.
Instead, you can call SendInput() yourself by P/Invoking. Here's a short but
complete sample as a console application. It uses .NET 3.5 and LINQ, but
this is just for convenience and you should have no trouble adapting it to
.NET 2.0 if required.

   using System;
   using System.Linq;
   using System.Windows.Forms;
   using System.Runtime.InteropServices;
   using System.Collections.Generic;
   using System.ComponentModel;

   [StructLayout(LayoutKind.Sequential)]
   public struct INPUT {
     public int type;
     public INPUTUNION inputUnion;
   }

   [StructLayout(LayoutKind.Explicit)]
   public struct INPUTUNION {
     // Fields
     [FieldOffset(0)]
     public HARDWAREINPUT hi;
     [FieldOffset(0)]
     public KEYBDINPUT ki;
     [FieldOffset(0)]
     public MOUSEINPUT mi;
   }

   [StructLayout(LayoutKind.Sequential)]
   public struct HARDWAREINPUT {
     public int uMsg;
     public short wParamL;
     public short wParamH;
   }

   [StructLayout(LayoutKind.Sequential)]
   public struct KEYBDINPUT {
     public short wVk;
     public short wScan;
     public int dwFlags;
     public int time;
     public IntPtr dwExtraInfo;
   }

   [StructLayout(LayoutKind.Sequential)]
   public struct MOUSEINPUT {
     public int dx;
     public int dy;
     public int mouseData;
     public int dwFlags;
     public int time;
     public IntPtr dwExtraInfo;
   }

   static class NativeMethods {
     [DllImport("user32.dll", SetLastError = true)]
     public static extern int SendInput(int nInputs, [In] INPUT[] pInputs,
int cbSize);
   }

   class Program {
     static int SendKeys(params Keys[] keys) {
       var nativeKeys = keys.Select(
         k => new INPUT {
           type = 1, inputUnion = new INPUTUNION {
             ki = new KEYBDINPUT { wVk = (short) k }
           }
         }
       ).ToArray();
       int keysSent = NativeMethods.SendInput(nativeKeys.Length, nativeKeys,
Marshal.SizeOf(typeof(INPUT)));
       if (keysSent == 0) throw new Win32Exception();
       return keysSent;
     }

     static void Main(string[] args) {
       while (true) {
         var cki = Console.ReadKey();
         switch (cki.KeyChar) {
           case 'q': Environment.Exit(0); break;
           case ' ': SendKeys(Keys.MediaPlayPause); break;
           case 'n': SendKeys(Keys.MediaNextTrack); break;
           case 'p': SendKeys(Keys.MediaPreviousTrack); break;
           case 's': SendKeys(Keys.MediaStop); break;
         }
       }
     }
   }
 
Thanks. I've tried using sendInput before, as well as keybd_event and
neither seems to do anything for the media keys. I'm trying it with
iTunes and Media Player, could it be that those 2 programs ignore
those keys, or should it work?
I can't test iTunes but I tested it with Winamp first, which worked fine.
I've now extended the test to Winamp, Media Player and Media Player Classic.

Winamp responds whether it has focus or not. In fact, if Winamp is running,
only Winamp will respond to the media player keys. Other media players don't
get to see the keys even if they're in focus. I'm guessing Winamp gets it
done with a global keyboard hook.

Media Player doesn't respond to the test program. Media Player does respond
if you touch the key physically, whether it has focus or not.

Media Player Classic only responds to the keys if it has focus. This means
the program doesn't work on it either. Pressing a media key when it's not in
focus does nothing.

Bottom line? Every application seems to have its own idea of when to respond
to the media keys. I don't know what the "right" way of doing what you want
is, if there is such a way.
 
Back
Top