Using Multimedia Keyboard Keys in Your Own Program | CodeGuru

Using Multimedia Keyboard Keys in Your Own Program

Environment: VS.NET (2003), Windows 2000, Windows XP When I bought my current computer, it came with a multimedia keyboard that has a lot more keys than usual. There are keys for controlling a media player and some browser keys, such as forward, back, and so forth. The Windows media player can be controlled by these […]

Written By
CodeGuru Staff
CodeGuru Staff
Aug 14, 2003
3 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Environment: VS.NET (2003), Windows 2000, Windows XP

When I bought my current computer, it came with a multimedia keyboard that has a lot more keys than usual. There are keys for controlling a media player and some browser keys, such as forward, back, and so forth.

The Windows media player can be controlled by these keys, even if it is in the background; this is a very convenient feature. My version of Winamp sadly does not make use of the keys.

When I looked for a MP3/Ogg player with an integrated media library and available source code (so I could change things if neccesary), I stumbled over Musik. This is a Linux/Windows MP3/Ogg player using wxwindows2 for the GUI and sqlite as the database. It is quite fast, at least faster than mediaplayer and musicmatch jukebox, concerning the startup time and media library browsing. It is available at http://musik.sf.net.

Musik also didn’t make use of the special keys, which I got accustomed to, so I started to add this feature for Windows. After reading some MSDN, I found out that you have to handle the WM_APPCOMMAND message, which is available to your program code, if you define _WIN32_WINNT=0x0500 (or higher) in your project. WM_APPCOMMAND can be found in winuser.h, if you have the right SDK headers. VS.NET already has these. For VC 6, I am not quite sure.

Your window proc of your window that should handle the WM_APPCOMMAND message has to do something like the following code does:

if(message == WM_APPCOMMAND)
{
  switch(GET_APPCOMMAND_LPARAM(lParam))
  {
  case APPCOMMAND_MEDIA_NEXTTRACK:
    // do something, which skips the track
    return 1;
  case APPCOMMAND_MEDIA_PREVIOUSTRACK:
    // do something…
    return 1;
  case APPCOMMAND_MEDIA_STOP:
    // do something, which stops playing
    return 1;
  case APPCOMMAND_MEDIA_PLAY_PAUSE:
    // toggle between play and pause
    return 1;
  }
}
// handle other messages or call default window proc.

This shows how to use the playing control keys, but you can use all other keys, too, if you use the corresponding APPCOMMAND_XXX code. (See MSDN or winuser.h for more.)

Now, by handling the WM_APPCOMMAND, your program will react to these keys, but only if the window with this windows proc is the active one, or one of its parent windows handles the message. If your program is not active, it will not get the message. So, what to do? The answer is that you have to write a DLL containg a shell hook. Windows will call a shell hook with the hook code equal to HSHELL_APPCOMMAND if the active program doesn’t handle the WM_APPCOMMAND message. This hook has to be in a DLL because only then can other processes than your own be hooked.

I have written such a hook DLL. The hook code just sends a WM_APPCOMMAND message every time the hook sees the HSHELL_APPCOMMAND code to a window that has installed the hook, by calling the SetMMShellHook(HWND hWnd) function of the hook DLL. To unregister, UnSetMMShellHook() has to be called. Call SetMMShellHook after creating your window and UnSetMMShellHook before it gets destroyed.

// Hook procedure for Shell hook
LRESULT CALLBACK ShellProc(int nCode, WPARAM wParam, LPARAM lParam)
{
  // Do we have to handle this?
  if (nCode == HSHELL_APPCOMMAND)
  {
    // Process the hook if the hNotifyWnd window handle is valid
    if (hNotifyWnd != NULL)
    {
      short AppCommand = GET_APPCOMMAND_LPARAM(lParam);
      switch (AppCommand)
      {
      case APPCOMMAND_MEDIA_NEXTTRACK:
      case APPCOMMAND_MEDIA_PLAY_PAUSE:
      case APPCOMMAND_MEDIA_PREVIOUSTRACK:
      case APPCOMMAND_MEDIA_STOP:
        ::PostMessage(hNotifyWnd,WM_APPCOMMAND,wParam,lParam);
        return 1; // Don’t call CallNextHookEx; instead,
                  // return non-zero, because we have handled
                  // the message (see MSDN doc)
      }
    }
  }
  // Call the next handler in the chain
  return CallNextHookEx (hShellHook, nCode, wParam, lParam);
}

This code only delegates some APPCOMMAD messages to the windows. You can add other ones, if you want, or delegate all, by removing the “switch case” and calling PostMessage every time.

Together with the window proc code above, your program reacts to the keys, even if it is in the background, but only if no application that handles the WM_APPCOMMAND is active. Then the keys will be handled by this application.

Because the hook has to be installed for different processes, the hook DLL makes use of a shared segment.

#pragma data_seg(“.shared”)
HWND  hNotifyWnd = NULL;
HHOOK hShellHook = NULL;    // Handle to the Shell hook
#pragma data_seg( )

This code declares a segment called “.shared”. To let this segment really become shared, you have to add a line in the .def file of the DLL. The linker has to learn of the def file by the /DEF: option.

SECTIONS
  .shared read write shared

Note: The .sln and vcproject files are for VS.NET 2003, but you can use them with VS.NET if you use a text editor to change the version to 7.00 in these files.

Have fun!

Downloads


Download source code – 5 Kb

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.