Skip to content

Commit

Permalink
Merge pull request #13049 from garbear/joystick-back
Browse files Browse the repository at this point in the history
Fix Back button in Android TV Remote Control app
  • Loading branch information
garbear committed Nov 17, 2017
2 parents 44e160d + 0e6f395 commit a2323e3
Show file tree
Hide file tree
Showing 14 changed files with 64 additions and 40 deletions.
9 changes: 8 additions & 1 deletion system/keymaps/joystick.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@
<rightstick direction="down">VolumeDown</rightstick>
</joystick>
</global>
<Home>
<joystick profile="game.controller.default">
<b>Back</b>
<b holdtime="500">ActivateWindow(ShutdownMenu)</b>
</joystick>
</Home>
<FileManager>
<joystick profile="game.controller.default">
<rightbumper>Highlight</rightbumper>
Expand All @@ -85,7 +91,8 @@
<FullscreenVideo>
<joystick profile="game.controller.default">
<a>Pause</a>
<b>Stop</b>
<b>Fullscreen</b>
<b holdtime="500">Stop</b>
<x>OSD</x>
<y>FullScreen</y>
<start>Info</start>
Expand Down
2 changes: 1 addition & 1 deletion xbmc/games/controllers/dialogs/GUIDialogButtonCapture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ bool CGUIDialogButtonCapture::MapPrimitive(JOYSTICK::IButtonMap* buttonMap,
std::string feature;
if (buttonMap->GetFeature(primitive, feature))
{
const auto &actions = keymap->GetActions(JOYSTICK::CJoystickUtils::MakeKeyName(feature));
const auto &actions = keymap->GetActions(JOYSTICK::CJoystickUtils::MakeKeyName(feature)).actions;
if (!actions.empty())
{
switch (actions.begin()->actionId)
Expand Down
2 changes: 1 addition & 1 deletion xbmc/games/controllers/windows/GUIConfigurationWizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ bool CGUIConfigurationWizard::MapPrimitive(JOYSTICK::IButtonMap* buttonMap,
std::string feature;
if (buttonMap->GetFeature(primitive, feature))
{
const auto &actions = keymap->GetActions(CJoystickUtils::MakeKeyName(feature));
const auto &actions = keymap->GetActions(CJoystickUtils::MakeKeyName(feature)).actions;
if (!actions.empty())
{
//! @todo Handle multiple actions mapped to the same key
Expand Down
4 changes: 2 additions & 2 deletions xbmc/input/IKeymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class IKeymap
*
* \return A list of actions associated with the given key
*/
virtual const KODI::JOYSTICK::KeymapActions& GetActions(const std::string& keyName) const = 0;
virtual const KODI::JOYSTICK::KeymapActionGroup& GetActions(const std::string& keyName) const = 0;
};

/*!
Expand Down Expand Up @@ -91,5 +91,5 @@ class IWindowKeymap
*
* \return A list of actions associated with the given key for the given window
*/
virtual const KODI::JOYSTICK::KeymapActions& GetActions(int windowId, const std::string& keyName) const = 0;
virtual const KODI::JOYSTICK::KeymapActionGroup& GetActions(int windowId, const std::string& keyName) const = 0;
};
16 changes: 8 additions & 8 deletions xbmc/input/Keymap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,28 @@ std::string CKeymap::ControllerID() const
return m_keymap->ControllerID();
}

const JOYSTICK::KeymapActions &CKeymap::GetActions(const std::string& keyName) const
const JOYSTICK::KeymapActionGroup &CKeymap::GetActions(const std::string& keyName) const
{
const int windowId = m_environment->GetWindowID();
const JOYSTICK::KeymapActions& actions = m_keymap->GetActions(windowId, keyName);
if (!actions.empty())
const auto &actions = m_keymap->GetActions(windowId, keyName);
if (!actions.actions.empty())
return actions;

const int fallbackWindowId = m_environment->GetFallthrough(windowId);
if (fallbackWindowId >= 0)
{
const JOYSTICK::KeymapActions& fallbackActions = m_keymap->GetActions(fallbackWindowId, keyName);
if (!fallbackActions.empty())
const auto &fallbackActions = m_keymap->GetActions(fallbackWindowId, keyName);
if (!fallbackActions.actions.empty())
return fallbackActions;
}

if (m_environment->UseGlobalFallthrough())
{
const JOYSTICK::KeymapActions& globalActions = m_keymap->GetActions(-1, keyName);
if (!globalActions.empty())
const auto &globalActions = m_keymap->GetActions(-1, keyName);
if (!globalActions.actions.empty())
return globalActions;
}

static const JOYSTICK::KeymapActions empty;
static const JOYSTICK::KeymapActionGroup empty{};
return empty;
}
2 changes: 1 addition & 1 deletion xbmc/input/Keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CKeymap : public IKeymap
// implementation of IKeymap
virtual std::string ControllerID() const override ;
virtual const IKeymapEnvironment *Environment() const override { return m_environment; }
const KODI::JOYSTICK::KeymapActions &GetActions(const std::string& keyName) const override;
const KODI::JOYSTICK::KeymapActionGroup &GetActions(const std::string& keyName) const override;

private:
// Construction parameters
Expand Down
9 changes: 6 additions & 3 deletions xbmc/input/WindowKeymap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ CWindowKeymap::CWindowKeymap(const std::string &controllerId) :

void CWindowKeymap::MapAction(int windowId, const std::string &keyName, JOYSTICK::KeymapAction action)
{
m_windowKeymap[windowId][keyName].insert(std::move(action));
auto &actionGroup = m_windowKeymap[windowId][keyName];

actionGroup.windowId = windowId;
actionGroup.actions.insert(std::move(action));
}

const JOYSTICK::KeymapActions &CWindowKeymap::GetActions(int windowId, const std::string& keyName) const
const JOYSTICK::KeymapActionGroup &CWindowKeymap::GetActions(int windowId, const std::string& keyName) const
{
auto it = m_windowKeymap.find(windowId);
if (it != m_windowKeymap.end())
Expand All @@ -43,6 +46,6 @@ const JOYSTICK::KeymapActions &CWindowKeymap::GetActions(int windowId, const std
return it2->second;
}

static const JOYSTICK::KeymapActions empty;
static const JOYSTICK::KeymapActionGroup empty{};
return empty;
}
4 changes: 2 additions & 2 deletions xbmc/input/WindowKeymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ class CWindowKeymap : public IWindowKeymap
// implementation of IWindowKeymap
virtual std::string ControllerID() const override { return m_controllerId; }
virtual void MapAction(int windowId, const std::string &keyName, KODI::JOYSTICK::KeymapAction action) override;
virtual const KODI::JOYSTICK::KeymapActions &GetActions(int windowId, const std::string& keyName) const override;
virtual const KODI::JOYSTICK::KeymapActionGroup &GetActions(int windowId, const std::string& keyName) const override;

private:
// Construction parameter
const std::string m_controllerId;

using KeyName = std::string;
using Keymap = std::map<KeyName, KODI::JOYSTICK::KeymapActions>;
using Keymap = std::map<KeyName, KODI::JOYSTICK::KeymapActionGroup>;

using WindowID = int;
using WindowMap = std::map<WindowID, Keymap>;
Expand Down
6 changes: 5 additions & 1 deletion xbmc/input/joysticks/JoystickTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ namespace JOYSTICK
* \ingroup joystick
* \brief Container that sorts action entries by their holdtime
*/
using KeymapActions = std::set<KeymapAction>;
struct KeymapActionGroup
{
int windowId = -1;
std::set<KeymapAction> actions;
};
}
}
2 changes: 0 additions & 2 deletions xbmc/input/joysticks/JoystickUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ class CJoystickUtils
* \param dir The direction for analog sticks, or ignored otherwise
*
* \return A valid name for a key in the joystick keymap
*
* \sa ParseKeyName()
*/
static std::string MakeKeyName(const FeatureName &feature, ANALOG_STICK_DIRECTION dir = ANALOG_STICK_DIRECTION::UNKNOWN);

Expand Down
2 changes: 1 addition & 1 deletion xbmc/input/joysticks/generic/ButtonMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ CButtonMapping::CButtonMapping(IButtonMapper* buttonMapper, IButtonMap* buttonMa
{
bool bIsSelectAction = false;

const auto &actions = m_keymap->GetActions(CJoystickUtils::MakeKeyName(feature.Name()));
const auto &actions = m_keymap->GetActions(CJoystickUtils::MakeKeyName(feature.Name())).actions;
if (!actions.empty() && actions.begin()->actionId == ACTION_SELECT_ITEM)
bIsSelectAction = true;

Expand Down
37 changes: 24 additions & 13 deletions xbmc/input/joysticks/keymaps/KeyHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ void CKeyHandler::Reset()
m_lastHoldTimeMs = 0;
m_bActionSent = false;
m_lastActionMs = 0;
m_activeWindowId = -1;
}

bool CKeyHandler::OnDigitalMotion(bool bPressed, unsigned int holdTimeMs)
Expand All @@ -72,6 +73,11 @@ bool CKeyHandler::OnAnalogMotion(float magnitude, unsigned int motionTimeMs)
if (m_magnitude == 0.0f && magnitude == 0.0f)
return false;

// Get actions for the key
const auto &actionGroup = m_keymap->GetActions(m_keyName);
const int windowId = actionGroup.windowId;
const auto &actions = actionGroup.actions;

// Calculate press state
const bool bPressed = IsPressed(magnitude);
const bool bJustPressed = bPressed && !m_bHeld;
Expand All @@ -83,16 +89,17 @@ bool CKeyHandler::OnAnalogMotion(float magnitude, unsigned int motionTimeMs)

// Record hold start time if just pressed
m_holdStartTimeMs = motionTimeMs;

// Record window ID
if (windowId >= 0)
m_activeWindowId = windowId;
}

// Calculate holdtime relative to when magnitude crossed the threshold
unsigned int holdTimeMs = 0;
if (bPressed)
holdTimeMs = motionTimeMs - m_holdStartTimeMs;

// Get actions for the key
const auto &actions = m_keymap->GetActions(m_keyName);

// Give priority to actions with hotkeys
std::vector<const KeymapAction*> actionsWithHotkeys;

Expand All @@ -102,7 +109,7 @@ bool CKeyHandler::OnAnalogMotion(float magnitude, unsigned int motionTimeMs)
actionsWithHotkeys.emplace_back(&action);
}

bool bHandled = HandleActions(std::move(actionsWithHotkeys), magnitude, holdTimeMs);
bool bHandled = HandleActions(std::move(actionsWithHotkeys), windowId, magnitude, holdTimeMs);

// If that failed, try again with all actions
if (!bHandled)
Expand All @@ -112,7 +119,7 @@ bool CKeyHandler::OnAnalogMotion(float magnitude, unsigned int motionTimeMs)
for (const auto &action : actions)
allActions.emplace_back(&action);

bHandled = HandleActions(std::move(allActions), magnitude, holdTimeMs);
bHandled = HandleActions(std::move(allActions), windowId, magnitude, holdTimeMs);
}

m_bHeld = bPressed;
Expand All @@ -122,7 +129,7 @@ bool CKeyHandler::OnAnalogMotion(float magnitude, unsigned int motionTimeMs)
return bHandled;
}

bool CKeyHandler::HandleActions(std::vector<const KeymapAction*> actions, float magnitude, unsigned int holdTimeMs)
bool CKeyHandler::HandleActions(std::vector<const KeymapAction*> actions, int windowId, float magnitude, unsigned int holdTimeMs)
{
// Filter out actions without pressed hotkeys
actions.erase(std::remove_if(actions.begin(), actions.end(),
Expand All @@ -144,7 +151,7 @@ bool CKeyHandler::HandleActions(std::vector<const KeymapAction*> actions, float
const bool bHasDelay = (maxHoldTimeMs > 0);
if (!bHasDelay)
{
bHandled = HandleAction(finalAction, magnitude, holdTimeMs);
bHandled = HandleAction(finalAction, windowId, magnitude, holdTimeMs);
}
else
{
Expand All @@ -157,7 +164,7 @@ bool CKeyHandler::HandleActions(std::vector<const KeymapAction*> actions, float
else
holdTimeMs -= finalAction.holdTimeMs;

bHandled = HandleAction(finalAction, magnitude, holdTimeMs);
bHandled = HandleAction(finalAction, windowId, magnitude, holdTimeMs);
}
else
{
Expand All @@ -167,14 +174,14 @@ bool CKeyHandler::HandleActions(std::vector<const KeymapAction*> actions, float

// If button was just released, send a release action
if (bJustReleased)
bHandled = HandleRelease(actions);
bHandled = HandleRelease(actions, windowId);
}
}

return bHandled;
}

bool CKeyHandler::HandleRelease(std::vector<const KeymapAction*> actions)
bool CKeyHandler::HandleRelease(std::vector<const KeymapAction*> actions, int windowId)
{
bool bHandled = false;

Expand All @@ -196,19 +203,23 @@ bool CKeyHandler::HandleRelease(std::vector<const KeymapAction*> actions)

if (thisHoldTime <= holdTimeMs && holdTimeMs < nextHoldTime)
{
bHandled = HandleAction(action, 1.0f, 0);
bHandled = HandleAction(action, windowId, 1.0f, 0);
break;
}
}

return bHandled;
}

bool CKeyHandler::HandleAction(const KeymapAction& action, float magnitude, unsigned int holdTimeMs)
bool CKeyHandler::HandleAction(const KeymapAction& action, int windowId, float magnitude, unsigned int holdTimeMs)
{
bool bSendAction = false;

if (CActionTranslator::IsAnalog(action.actionId))
if (windowId != m_activeWindowId)
{
// Don't send actions if the window has changed since being pressed
}
else if (CActionTranslator::IsAnalog(action.actionId))
{
bSendAction = true;
}
Expand Down
7 changes: 4 additions & 3 deletions xbmc/input/joysticks/keymaps/KeyHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ namespace JOYSTICK
private:
void Reset();

bool HandleActions(std::vector<const KeymapAction*> actions, float magnitude, unsigned int holdTimeMs);
bool HandleRelease(std::vector<const KeymapAction*> actions);
bool HandleActions(std::vector<const KeymapAction*> actions, int windowId, float magnitude, unsigned int holdTimeMs);
bool HandleRelease(std::vector<const KeymapAction*> actions, int windowId);

bool HandleAction(const KeymapAction& action, float magnitude, unsigned int holdTimeMs);
bool HandleAction(const KeymapAction& action, int windowId, float magnitude, unsigned int holdTimeMs);

// Check criteria for sending a repeat action
bool SendRepeatAction(unsigned int holdTimeMs);
Expand All @@ -79,6 +79,7 @@ namespace JOYSTICK
unsigned int m_lastHoldTimeMs;
bool m_bActionSent;
unsigned int m_lastActionMs;
int m_activeWindowId = -1; // Window that activated the key
};
}
}
2 changes: 1 addition & 1 deletion xbmc/input/joysticks/keymaps/KeymapHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ bool CKeymapHandler::HasAction(const std::string &keyName) const
{
bool bHasAction = false;

const auto &actions = m_keymap->GetActions(keyName);
const auto &actions = m_keymap->GetActions(keyName).actions;
for (const auto &action : actions)
{
if (HotkeysPressed(action.hotkeys))
Expand Down

0 comments on commit a2323e3

Please sign in to comment.