Permalink
Browse files

Allow WM_APPCOMMAND messages to be mappable like key presses

  • Loading branch information...
1 parent fb86f1e commit e38894acabcae5934031fa16b56f10b36e6238bb John Rennie committed May 24, 2011
@@ -0,0 +1,24 @@
+<keymap>
+ <global>
+ <appcommand>
+ <browser_backward>ParentDir</browser_backward>
+ <browser_forward/>
+ <browser_refresh/>
+ <browser_stop>Stop</browser_stop>
+ <browser_search/>
+ <browser_favorites>ActivateWindow(Favourites)</browser_favorites>
+ <browser_home>FirstPage</browser_home>
+ <volume_mute/>
+ <volume_down/>
+ <volume_up/>
+ <media_nexttrack>SkipNext</media_nexttrack>
+ <media_previoustrack>SkipPrevious</media_previoustrack>
+ <media_stop>Stop</media_stop>
+ <media_play_pause>Play</media_play_pause>
+ <launch_mail/>
+ <launch_media_select>XBMC.ActivateWindow(MyMusic)</launch_media_select>
+ <launch_app1>ActivateWindow(MyPrograms)</launch_app1>
+ <launch_app2>ActivateWindow(MyPrograms)</launch_app2>
+ </appcommand>
+ </global>
+</keymap>
View
@@ -393,12 +393,7 @@ bool CApplication::OnEvent(XBMC_Event& newEvent)
g_application.getApplicationMessenger().UserEvent(newEvent.user.code);
break;
case XBMC_APPCOMMAND:
- {
- // Special media keys are mapped to WM_APPCOMMAND on Windows (and to DBUS events on Linux?)
- // XBMC translates WM_APPCOMMAND to XBMC_APPCOMMAND events.
- g_application.OnAppCommand(CAction(newEvent.appcommand.action));
- }
- break;
+ return g_application.OnAppCommand(newEvent.appcommand.action);
}
return true;
}
@@ -2361,20 +2356,38 @@ bool CApplication::OnKey(const CKey& key)
}
// OnAppCommand is called in response to a XBMC_APPCOMMAND event.
-
+// This needs to return 1 if it processed the appcommand or zero if it didn't
bool CApplication::OnAppCommand(const CAction &action)
{
// Reset the screen saver
ResetScreenSaver();
// If we were currently in the screen saver wake up and don't process the appcommand
if (WakeUpScreenSaverAndDPMS())
- {
return true;
+
+ // The action ID is the APPCOMMAND code. We need to retrieve the action
+ // associated with this appcommand from the mapping table.
+ uint32_t appcmd = action.GetID();
+ CKey key(appcmd | KEY_APPCOMMAND, (unsigned int) 0);
+ int iWin = g_windowManager.GetActiveWindow() & WINDOW_ID_MASK;
+ CAction appcmdaction = CButtonTranslator::GetInstance().GetAction(iWin, key);
+
+ // If we couldn't find an action return zero to indicate we have not
+ // handled this appcommand
+ if (!appcmdaction.GetID())
+ {
+ CLog::Log(LOGDEBUG, "%s: unknown appcommand %d", __FUNCTION__, appcmd);
+ return 0;
}
// Process the appcommand
- return OnAction(action);
+ CLog::Log(LOGDEBUG, "%s: appcommand %d, trying action %s", __FUNCTION__, appcmd, appcmdaction.GetName().c_str());
+ OnAction(appcmdaction);
+
+ // Always return 1 regardless of whether the action succeeded or not.
+ // This stops Windows handling the appcommand itself.
+ return 1;
}
bool CApplication::OnAction(const CAction &action)
View
@@ -76,6 +76,9 @@
#define KEY_ASCII 0xF100 // a printable character in the range of TRUE ASCII (from 0 to 127) // FIXME make it clean and pure unicode! remove the need for KEY_ASCII
#define KEY_UNICODE 0xF200 // another printable character whose range is not included in this KEY code
+// 0xD000 -> 0xD0FF is reserved for WM_APPCOMMAND messages
+#define KEY_APPCOMMAND 0xD000
+
#define KEY_INVALID 0xFFFF
// actions that we have defined...
@@ -291,6 +291,29 @@ static const ActionMapping windows[] =
{"startwindow" , WINDOW_START},
{"startup" , WINDOW_STARTUP_ANIM}};
+#ifdef WIN32
+static const ActionMapping appcommands[] =
+{
+ { "browser_backward", APPCOMMAND_BROWSER_BACKWARD },
+ { "browser_forward", APPCOMMAND_BROWSER_FORWARD },
+ { "browser_refresh", APPCOMMAND_BROWSER_REFRESH },
+ { "browser_stop", APPCOMMAND_BROWSER_STOP },
+ { "browser_search", APPCOMMAND_BROWSER_SEARCH },
+ { "browser_favorites", APPCOMMAND_BROWSER_FAVORITES },
+ { "browser_home", APPCOMMAND_BROWSER_HOME },
+ { "volume_mute", APPCOMMAND_VOLUME_MUTE },
+ { "volume_down", APPCOMMAND_VOLUME_DOWN },
+ { "volume_up", APPCOMMAND_VOLUME_UP },
+ { "media_nexttrack", APPCOMMAND_MEDIA_NEXTTRACK },
+ { "media_previoustrack", APPCOMMAND_MEDIA_PREVIOUSTRACK },
+ { "media_stop", APPCOMMAND_MEDIA_STOP },
+ { "media_play_pause", APPCOMMAND_MEDIA_PLAY_PAUSE },
+ { "launch_mail", APPCOMMAND_LAUNCH_MAIL },
+ { "launch_media_select", APPCOMMAND_LAUNCH_MEDIA_SELECT },
+ { "launch_app1", APPCOMMAND_LAUNCH_APP1 },
+ { "launch_app2", APPCOMMAND_LAUNCH_APP2 }
+};
+#endif
CButtonTranslator& CButtonTranslator::GetInstance()
{
@@ -799,7 +822,7 @@ void CButtonTranslator::MapWindowActions(TiXmlNode *pWindow, int windowID)
}
TiXmlNode* pDevice;
- const char* types[] = {"gamepad", "remote", "keyboard", "universalremote", NULL};
+ const char* types[] = {"gamepad", "remote", "universalremote", "keyboard", "appcommand", NULL};
for (int i = 0; types[i]; ++i)
{
CStdString type(types[i]);
@@ -818,6 +841,8 @@ void CButtonTranslator::MapWindowActions(TiXmlNode *pWindow, int windowID)
buttonCode = TranslateUniversalRemoteString(pButton->Value());
else if (type == "keyboard")
buttonCode = TranslateKeyboardButton(pButton);
+ else if (type == "appcommand")
+ buttonCode = TranslateAppCommand(pButton->Value());
if (buttonCode && pButton->FirstChild())
MapAction(buttonCode, pButton->FirstChild()->Value(), map);
@@ -1104,6 +1129,22 @@ uint32_t CButtonTranslator::TranslateKeyboardButton(TiXmlElement *pButton)
return button_id;
}
+uint32_t CButtonTranslator::TranslateAppCommand(const char *szButton)
+{
+#ifdef WIN32
+ CStdString strAppCommand = szButton;
+ strAppCommand.ToLower();
+
+ for (int i = 0; i < sizeof(appcommands)/sizeof(appcommands[0]); i++)
+ if (strAppCommand.Equals(appcommands[i].name))
+ return appcommands[i].action | KEY_APPCOMMAND;
+
+ CLog::Log(LOGERROR, "%s: Can't find appcommand %s", __FUNCTION__, szButton);
+#endif
+
+ return 0;
+}
+
void CButtonTranslator::Clear()
{
translatorMap.clear();
@@ -106,6 +106,8 @@ class CButtonTranslator
static uint32_t TranslateKeyboardString(const char *szButton);
static uint32_t TranslateKeyboardButton(TiXmlElement *pButton);
+ static uint32_t CButtonTranslator::TranslateAppCommand(const char *szButton);
+
void MapWindowActions(TiXmlNode *pWindow, int wWindowID);
void MapAction(uint32_t buttonCode, const char *szAction, buttonMap &map);
@@ -500,47 +500,8 @@ LRESULT CALLBACK CWinEventsWin32::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, L
{
CLog::Log(LOGDEBUG, "WinEventsWin32.cpp: APPCOMMAND %d", GET_APPCOMMAND_LPARAM(lParam));
newEvent.appcommand.type = XBMC_APPCOMMAND;
- newEvent.appcommand.action = 0;
-
- switch (GET_APPCOMMAND_LPARAM(lParam))
- {
- case APPCOMMAND_MEDIA_PLAY:
- newEvent.appcommand.action = ACTION_PLAYER_PLAY;
- break;
- case APPCOMMAND_MEDIA_PLAY_PAUSE:
- newEvent.appcommand.action = ACTION_PLAYER_PLAYPAUSE;
- break;
- case APPCOMMAND_MEDIA_PAUSE:
- newEvent.appcommand.action = ACTION_PAUSE;
- break;
- case APPCOMMAND_BROWSER_BACKWARD:
- newEvent.appcommand.action = ACTION_PARENT_DIR;
- break;
- case APPCOMMAND_MEDIA_STOP:
- newEvent.appcommand.action = ACTION_STOP;
- break;
- case APPCOMMAND_MEDIA_PREVIOUSTRACK:
- newEvent.appcommand.action = ACTION_PREV_ITEM;
- break;
- case APPCOMMAND_MEDIA_NEXTTRACK:
- newEvent.appcommand.action = ACTION_NEXT_ITEM;
- break;
- case APPCOMMAND_MEDIA_REWIND:
- newEvent.appcommand.action = ACTION_PLAYER_REWIND;
- break;
- case APPCOMMAND_MEDIA_FAST_FORWARD:
- newEvent.appcommand.action = ACTION_PLAYER_FORWARD;
- break;
- case APPCOMMAND_LAUNCH_MEDIA_SELECT:
- // disable launch of external media players
- return 1;
- }
- if (newEvent.appcommand.action != 0)
- {
- m_pEventFunc(newEvent);
- return 1; // should return TRUE if application handled the event
- }
- break;
+ newEvent.appcommand.action = GET_APPCOMMAND_LPARAM(lParam);
+ return m_pEventFunc(newEvent);
}
case WM_GESTURENOTIFY:
{

0 comments on commit e38894a

Please sign in to comment.