summaryrefslogtreecommitdiffstats
path: root/xbmc/input/mouse
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/input/mouse')
-rw-r--r--xbmc/input/mouse/CMakeLists.txt13
-rw-r--r--xbmc/input/mouse/MouseStat.cpp378
-rw-r--r--xbmc/input/mouse/MouseStat.h227
-rw-r--r--xbmc/input/mouse/MouseTranslator.cpp135
-rw-r--r--xbmc/input/mouse/MouseTranslator.h34
-rw-r--r--xbmc/input/mouse/MouseTypes.h55
-rw-r--r--xbmc/input/mouse/generic/CMakeLists.txt5
-rw-r--r--xbmc/input/mouse/generic/MouseInputHandling.cpp352
-rw-r--r--xbmc/input/mouse/generic/MouseInputHandling.h66
-rw-r--r--xbmc/input/mouse/interfaces/IMouseDriverHandler.h56
-rw-r--r--xbmc/input/mouse/interfaces/IMouseInputHandler.h66
-rw-r--r--xbmc/input/mouse/interfaces/IMouseInputProvider.h43
12 files changed, 1430 insertions, 0 deletions
diff --git a/xbmc/input/mouse/CMakeLists.txt b/xbmc/input/mouse/CMakeLists.txt
new file mode 100644
index 0000000..214adf0
--- /dev/null
+++ b/xbmc/input/mouse/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(SOURCES MouseStat.cpp
+ MouseTranslator.cpp
+)
+
+set(HEADERS interfaces/IMouseDriverHandler.h
+ interfaces/IMouseInputHandler.h
+ interfaces/IMouseInputProvider.h
+ MouseStat.h
+ MouseTranslator.h
+ MouseTypes.h
+)
+
+core_add_library(input_mouse)
diff --git a/xbmc/input/mouse/MouseStat.cpp b/xbmc/input/mouse/MouseStat.cpp
new file mode 100644
index 0000000..8b6ce3b
--- /dev/null
+++ b/xbmc/input/mouse/MouseStat.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "MouseStat.h"
+
+#include "ServiceBroker.h"
+#include "input/Key.h"
+#include "utils/TimeUtils.h"
+#include "windowing/WinSystem.h"
+
+#include <algorithm>
+#include <cstring>
+
+CMouseStat::CMouseStat()
+{
+ SetEnabled();
+ m_Key = KEY_MOUSE_NOOP;
+}
+
+CMouseStat::~CMouseStat() = default;
+
+void CMouseStat::Initialize()
+{
+ // Set the default resolution (PAL)
+ SetResolution(720, 576, 1, 1);
+}
+
+void CMouseStat::HandleEvent(const XBMC_Event& newEvent)
+{
+ // Save the mouse position and the size of the last move
+ int dx, dy;
+ if (newEvent.type == XBMC_MOUSEMOTION)
+ {
+ dx = newEvent.motion.x - m_mouseState.x;
+ dy = newEvent.motion.y - m_mouseState.y;
+ }
+ else if (newEvent.type == XBMC_MOUSEBUTTONDOWN || newEvent.type == XBMC_MOUSEBUTTONUP)
+ {
+ dx = newEvent.button.x - m_mouseState.x;
+ dy = newEvent.button.y - m_mouseState.y;
+ }
+ else
+ {
+ return;
+ }
+ m_mouseState.dx = dx;
+ m_mouseState.dy = dy;
+ m_mouseState.x = std::max(0, std::min(m_maxX, m_mouseState.x + dx));
+ m_mouseState.y = std::max(0, std::min(m_maxY, m_mouseState.y + dy));
+
+ // Fill in the public members
+ if (newEvent.type == XBMC_MOUSEBUTTONDOWN)
+ {
+ if (newEvent.button.button == XBMC_BUTTON_LEFT)
+ m_mouseState.button[MOUSE_LEFT_BUTTON] = true;
+ if (newEvent.button.button == XBMC_BUTTON_RIGHT)
+ m_mouseState.button[MOUSE_RIGHT_BUTTON] = true;
+ if (newEvent.button.button == XBMC_BUTTON_MIDDLE)
+ m_mouseState.button[MOUSE_MIDDLE_BUTTON] = true;
+ if (newEvent.button.button == XBMC_BUTTON_X1)
+ m_mouseState.button[MOUSE_EXTRA_BUTTON1] = true;
+ if (newEvent.button.button == XBMC_BUTTON_X2)
+ m_mouseState.button[MOUSE_EXTRA_BUTTON2] = true;
+ if (newEvent.button.button == XBMC_BUTTON_X3)
+ m_mouseState.button[MOUSE_EXTRA_BUTTON3] = true;
+ if (newEvent.button.button == XBMC_BUTTON_X4)
+ m_mouseState.button[MOUSE_EXTRA_BUTTON4] = true;
+ if (newEvent.button.button == XBMC_BUTTON_WHEELUP)
+ m_mouseState.dz = 1;
+ if (newEvent.button.button == XBMC_BUTTON_WHEELDOWN)
+ m_mouseState.dz = -1;
+ }
+ else if (newEvent.type == XBMC_MOUSEBUTTONUP)
+ {
+ if (newEvent.button.button == XBMC_BUTTON_LEFT)
+ m_mouseState.button[MOUSE_LEFT_BUTTON] = false;
+ if (newEvent.button.button == XBMC_BUTTON_RIGHT)
+ m_mouseState.button[MOUSE_RIGHT_BUTTON] = false;
+ if (newEvent.button.button == XBMC_BUTTON_MIDDLE)
+ m_mouseState.button[MOUSE_MIDDLE_BUTTON] = false;
+ if (newEvent.button.button == XBMC_BUTTON_X1)
+ m_mouseState.button[MOUSE_EXTRA_BUTTON1] = false;
+ if (newEvent.button.button == XBMC_BUTTON_X2)
+ m_mouseState.button[MOUSE_EXTRA_BUTTON2] = false;
+ if (newEvent.button.button == XBMC_BUTTON_X3)
+ m_mouseState.button[MOUSE_EXTRA_BUTTON3] = false;
+ if (newEvent.button.button == XBMC_BUTTON_X4)
+ m_mouseState.button[MOUSE_EXTRA_BUTTON4] = false;
+ if (newEvent.button.button == XBMC_BUTTON_WHEELUP)
+ m_mouseState.dz = 0;
+ if (newEvent.button.button == XBMC_BUTTON_WHEELDOWN)
+ m_mouseState.dz = 0;
+ }
+
+ // Now check the current message and the previous state to find out if
+ // this is a click, doubleclick, drag etc
+ uint32_t now = CTimeUtils::GetFrameTime();
+ bool bNothingDown = true;
+
+ for (int i = 0; i < MOUSE_MAX_BUTTON; i++)
+ {
+ bClick[i] = false;
+ bLongClick[i] = false;
+ bDoubleClick[i] = false;
+ m_hold[i] = HoldAction::NONE;
+
+ // CButtonState::Update does the hard work of checking the button state
+ // and spotting drags, doubleclicks etc
+ CButtonState::BUTTON_ACTION action =
+ m_buttonState[i].Update(now, m_mouseState.x, m_mouseState.y, m_mouseState.button[i]);
+ switch (action)
+ {
+ case CButtonState::MB_SHORT_CLICK:
+ bClick[i] = true;
+ bNothingDown = false;
+ break;
+ case CButtonState::MB_LONG_CLICK:
+ bLongClick[i] = true;
+ bNothingDown = false;
+ break;
+ case CButtonState::MB_DOUBLE_CLICK:
+ bDoubleClick[i] = true;
+ bNothingDown = false;
+ break;
+ case CButtonState::MB_DRAG_START:
+ m_hold[i] = HoldAction::DRAG_START;
+ bNothingDown = false;
+ break;
+ case CButtonState::MB_DRAG:
+ m_hold[i] = HoldAction::DRAG;
+ bNothingDown = false;
+ break;
+ case CButtonState::MB_DRAG_END:
+ m_hold[i] = HoldAction::DRAG_END;
+ bNothingDown = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Now work out what action ID to send to XBMC.
+
+ // ignore any mouse messages by default
+ m_Key = KEY_MOUSE_NOOP;
+
+ for (int button = 0; button < MOUSE_MAX_BUTTON; ++button)
+ {
+ // The bClick array is set true if CButtonState::Update spots a click
+ // i.e. a button down followed by a button up.
+ if (bClick[button])
+ m_Key = KEY_MOUSE_CLICK + button;
+ // The bDoubleClick array is set true if CButtonState::Update spots a
+ // button down within double_click_time (500ms) of the last click
+ else if (bDoubleClick[button])
+ m_Key = KEY_MOUSE_DOUBLE_CLICK + button;
+ else if (bLongClick[button])
+ m_Key = KEY_MOUSE_LONG_CLICK + button;
+
+ if (m_Key != KEY_MOUSE_NOOP)
+ break;
+ }
+
+ if (m_Key == KEY_MOUSE_NOOP)
+ {
+ // The m_hold array is set to the drag action
+ if (m_hold[MOUSE_LEFT_BUTTON] != HoldAction::NONE)
+ {
+ switch (m_hold[MOUSE_LEFT_BUTTON])
+ {
+ case HoldAction::DRAG:
+ m_Key = KEY_MOUSE_DRAG;
+ break;
+ case HoldAction::DRAG_START:
+ m_Key = KEY_MOUSE_DRAG_START;
+ break;
+ case HoldAction::DRAG_END:
+ m_Key = KEY_MOUSE_DRAG_END;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (m_hold[MOUSE_RIGHT_BUTTON] != HoldAction::NONE)
+ {
+ switch (m_hold[MOUSE_RIGHT_BUTTON])
+ {
+ case HoldAction::DRAG:
+ m_Key = KEY_MOUSE_RDRAG;
+ break;
+ case HoldAction::DRAG_START:
+ m_Key = KEY_MOUSE_RDRAG_START;
+ break;
+ case HoldAction::DRAG_END:
+ m_Key = KEY_MOUSE_RDRAG_END;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // dz is +1 on wheel up and -1 on wheel down
+ else if (m_mouseState.dz > 0)
+ m_Key = KEY_MOUSE_WHEEL_UP;
+ else if (m_mouseState.dz < 0)
+ m_Key = KEY_MOUSE_WHEEL_DOWN;
+
+ // Check for a mouse move that isn't a drag, ignoring messages with no movement at all
+ else if (newEvent.type == XBMC_MOUSEMOTION && (m_mouseState.dx || m_mouseState.dy))
+ m_Key = KEY_MOUSE_MOVE;
+ }
+
+ // activate the mouse pointer if we have an action or the mouse has moved far enough
+ if ((MovedPastThreshold() && m_Key == KEY_MOUSE_MOVE) ||
+ (m_Key != KEY_MOUSE_NOOP && m_Key != KEY_MOUSE_MOVE))
+ SetActive();
+
+ // reset the mouse state if nothing is held down
+ if (bNothingDown)
+ SetState(MOUSE_STATE_NORMAL);
+}
+
+void CMouseStat::SetResolution(int maxX, int maxY, float speedX, float speedY)
+{
+ m_maxX = maxX;
+ m_maxY = maxY;
+
+ // speed is currently unused
+ m_speedX = speedX;
+ m_speedY = speedY;
+}
+
+void CMouseStat::SetActive(bool active /*=true*/)
+{
+ m_lastActiveTime = CTimeUtils::GetFrameTime();
+ m_mouseState.active = active;
+ // we show the OS mouse if:
+ // 1. The mouse is active (it has been moved) AND
+ // 2. The XBMC mouse is disabled in settings AND
+ // 3. XBMC is not in fullscreen.
+ CWinSystemBase* winSystem = CServiceBroker::GetWinSystem();
+ if (winSystem)
+ winSystem->ShowOSMouse(m_mouseState.active && !IsEnabled() &&
+ !CServiceBroker::GetWinSystem()->IsFullScreen());
+}
+
+// IsActive - returns true if we have been active in the last MOUSE_ACTIVE_LENGTH period
+bool CMouseStat::IsActive()
+{
+ if (m_mouseState.active && (CTimeUtils::GetFrameTime() - m_lastActiveTime > MOUSE_ACTIVE_LENGTH))
+ SetActive(false);
+ return (m_mouseState.active && IsEnabled());
+}
+
+void CMouseStat::SetEnabled(bool enabled)
+{
+ m_mouseEnabled = enabled;
+ SetActive(enabled);
+}
+
+// IsEnabled - returns true if mouse is enabled
+bool CMouseStat::IsEnabled() const
+{
+ return m_mouseEnabled;
+}
+
+bool CMouseStat::MovedPastThreshold() const
+{
+ return (m_mouseState.dx * m_mouseState.dx + m_mouseState.dy * m_mouseState.dy >=
+ MOUSE_MINIMUM_MOVEMENT * MOUSE_MINIMUM_MOVEMENT);
+}
+
+uint32_t CMouseStat::GetKey() const
+{
+ return m_Key;
+}
+
+HoldAction CMouseStat::GetHold(int ButtonID) const
+{
+ switch (ButtonID)
+ {
+ case MOUSE_LEFT_BUTTON:
+ return m_hold[MOUSE_LEFT_BUTTON];
+ }
+ return HoldAction::NONE;
+}
+
+CMouseStat::CButtonState::CButtonState()
+{
+ m_state = STATE_RELEASED;
+ m_time = 0;
+ m_x = 0;
+ m_y = 0;
+}
+
+bool CMouseStat::CButtonState::InClickRange(int x, int y) const
+{
+ int dx = x - m_x;
+ int dy = y - m_y;
+ return (unsigned int)(dx * dx + dy * dy) <= click_confines * click_confines;
+}
+
+CMouseStat::CButtonState::BUTTON_ACTION CMouseStat::CButtonState::Update(unsigned int time,
+ int x,
+ int y,
+ bool down)
+{
+ if (m_state == STATE_IN_DRAG)
+ {
+ if (down)
+ return MB_DRAG;
+ m_state = STATE_RELEASED;
+ return MB_DRAG_END;
+ }
+ else if (m_state == STATE_RELEASED)
+ {
+ if (down)
+ {
+ m_state = STATE_IN_CLICK;
+ m_time = time;
+ m_x = x;
+ m_y = y;
+ }
+ }
+ else if (m_state == STATE_IN_CLICK)
+ {
+ if (down)
+ {
+ if (!InClickRange(x, y))
+ { // beginning a drag
+ m_state = STATE_IN_DRAG;
+ return MB_DRAG_START;
+ }
+ }
+ else
+ { // button up
+ if (time - m_time < short_click_time)
+ { // single click
+ m_state = STATE_IN_DOUBLE_CLICK;
+ m_time = time; // double click time and positioning is measured from the
+ m_x = x; // end of a single click
+ m_y = y;
+ return MB_SHORT_CLICK;
+ }
+ else
+ { // long click
+ m_state = STATE_RELEASED;
+ return MB_LONG_CLICK;
+ }
+ }
+ }
+ else if (m_state == STATE_IN_DOUBLE_CLICK)
+ {
+ if (time - m_time > double_click_time || !InClickRange(x, y))
+ { // too long, or moved to much - reset to released state and re-update, as we may be starting a
+ // new click
+ m_state = STATE_RELEASED;
+ return Update(time, x, y, down);
+ }
+ if (down)
+ {
+ m_state = STATE_IN_DOUBLE_IGNORE;
+ return MB_DOUBLE_CLICK;
+ }
+ }
+ else if (m_state == STATE_IN_DOUBLE_IGNORE)
+ {
+ if (!down)
+ m_state = STATE_RELEASED;
+ }
+
+ return MB_NONE;
+}
diff --git a/xbmc/input/mouse/MouseStat.h b/xbmc/input/mouse/MouseStat.h
new file mode 100644
index 0000000..354d1c3
--- /dev/null
+++ b/xbmc/input/mouse/MouseStat.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "windowing/XBMC_events.h"
+
+#define XBMC_BUTTON(X) (1 << ((X)-1))
+#define XBMC_BUTTON_LEFT 1
+#define XBMC_BUTTON_MIDDLE 2
+#define XBMC_BUTTON_RIGHT 3
+#define XBMC_BUTTON_WHEELUP 4
+#define XBMC_BUTTON_WHEELDOWN 5
+#define XBMC_BUTTON_X1 6
+#define XBMC_BUTTON_X2 7
+#define XBMC_BUTTON_X3 8
+#define XBMC_BUTTON_X4 9
+#define XBMC_BUTTON_LMASK XBMC_BUTTON(XBMC_BUTTON_LEFT)
+#define XBMC_BUTTON_MMASK XBMC_BUTTON(XBMC_BUTTON_MIDDLE)
+#define XBMC_BUTTON_RMASK XBMC_BUTTON(XBMC_BUTTON_RIGHT)
+#define XBMC_BUTTON_X1MASK XBMC_BUTTON(XBMC_BUTTON_X1)
+#define XBMC_BUTTON_X2MASK XBMC_BUTTON(XBMC_BUTTON_X2)
+#define XBMC_BUTTON_X3MASK XBMC_BUTTON(XBMC_BUTTON_X3)
+#define XBMC_BUTTON_X4MASK XBMC_BUTTON(XBMC_BUTTON_X4)
+
+#define MOUSE_MINIMUM_MOVEMENT 2
+#define MOUSE_DOUBLE_CLICK_LENGTH 500L
+#define MOUSE_ACTIVE_LENGTH 5000L
+
+#define MOUSE_MAX_BUTTON 7
+
+enum MOUSE_STATE
+{
+ /*! Normal state */
+ MOUSE_STATE_NORMAL = 1,
+ /*! Control below the mouse is currently in focus */
+ MOUSE_STATE_FOCUS,
+ /*! A drag operation is being performed */
+ MOUSE_STATE_DRAG,
+ /*! A mousebutton is being clicked */
+ MOUSE_STATE_CLICK
+};
+
+enum MOUSE_BUTTON
+{
+ MOUSE_LEFT_BUTTON = 0,
+ MOUSE_RIGHT_BUTTON,
+ MOUSE_MIDDLE_BUTTON,
+ MOUSE_EXTRA_BUTTON1,
+ MOUSE_EXTRA_BUTTON2,
+ MOUSE_EXTRA_BUTTON3,
+ MOUSE_EXTRA_BUTTON4
+};
+
+enum class HoldAction
+{
+ /*! No action should occur */
+ NONE,
+ /*! A drag action has started */
+ DRAG_START,
+ /*! A drag action is in progress */
+ DRAG,
+ /*! A drag action has finished */
+ DRAG_END
+};
+
+//! Holds everything we know about the current state of the mouse
+struct MouseState
+{
+ /*! X location */
+ int x;
+ /*! Y location */
+ int y;
+ /*! Change in x */
+ int16_t dx;
+ /*! Change in y */
+ int16_t dy;
+ /*! Change in z (wheel) */
+ int8_t dz;
+ /*! Current state of the buttons */
+ bool button[MOUSE_MAX_BUTTON];
+ /*! True if the mouse is active */
+ bool active;
+};
+
+struct MousePosition
+{
+ int x;
+ int y;
+};
+
+class CAction;
+
+class CMouseStat
+{
+public:
+ CMouseStat();
+ virtual ~CMouseStat();
+
+ void Initialize();
+ void HandleEvent(const XBMC_Event& newEvent);
+ void SetResolution(int maxX, int maxY, float speedX, float speedY);
+ bool IsActive();
+ bool IsEnabled() const;
+
+ void SetActive(bool active = true);
+ void SetState(MOUSE_STATE state) { m_pointerState = state; }
+ void SetEnabled(bool enabled = true);
+ MOUSE_STATE GetState() const { return m_pointerState; }
+ uint32_t GetKey() const;
+
+ HoldAction GetHold(int ButtonID) const;
+ inline int GetX(void) const { return m_mouseState.x; }
+ inline int GetY(void) const { return m_mouseState.y; }
+ inline int GetDX(void) const { return m_mouseState.dx; }
+ inline int GetDY(void) const { return m_mouseState.dy; }
+ MousePosition GetPosition() { return MousePosition{m_mouseState.x, m_mouseState.y}; }
+
+private:
+ /*! \brief Holds information regarding a particular mouse button state
+
+ The CButtonState class is used to track where in a button event the mouse currently is.
+ There is effectively 5 BUTTON_STATE's available, and transitioning between those states
+ is handled by the Update() function.
+
+ The actions we detect are:
+ * short clicks - down/up press of the mouse within short_click_time ms, where the pointer stays
+ within click_confines pixels
+ * long clicks - down/up press of the mouse greater than short_click_time ms, where the pointers
+ stays within click_confines pixels
+ * double clicks - a further down press of the mouse within double_click_time of the up press of
+ a short click, where the pointer stays within click_confines pixels
+ * drag - the mouse is down and has been moved more than click_confines pixels
+
+ \sa CMouseStat
+ */
+ class CButtonState
+ {
+ public:
+ /*! \brief enum for the actions to perform as a result of an Update function
+ */
+ enum BUTTON_ACTION
+ {
+ MB_NONE = 0, ///< no action should occur
+ MB_SHORT_CLICK, ///< a short click has occurred (a double click may be in process)
+ MB_LONG_CLICK, ///< a long click has occurred
+ MB_DOUBLE_CLICK, ///< a double click has occurred
+ MB_DRAG_START, ///< a drag action has started
+ MB_DRAG, ///< a drag action is in progress
+ MB_DRAG_END
+ }; ///< a drag action has finished
+
+ CButtonState();
+
+ /*! \brief Update the button state, with where the mouse is, and whether the button is down or
+ not
+
+ \param time frame time in ms
+ \param x horizontal coordinate of the mouse
+ \param y vertical coordinate of the mouse
+ \param down true if the button is down
+ \return action that should be performed
+ */
+ BUTTON_ACTION Update(unsigned int time, int x, int y, bool down);
+
+ private:
+ //! number of pixels that the pointer may move while the button is down to
+ //! trigger a click
+ static const unsigned int click_confines = 5;
+
+ //! Time for mouse down/up to trigger a short click rather than a long click
+ static const unsigned int short_click_time = 1000;
+
+ //! Time for mouse down following a short click to trigger a double click
+ static const unsigned int double_click_time = 500;
+
+ bool InClickRange(int x, int y) const;
+
+ enum BUTTON_STATE
+ {
+ STATE_RELEASED = 0, ///< mouse button is released, no events pending
+ STATE_IN_CLICK, ///< mouse button is down, a click is pending
+ STATE_IN_DOUBLE_CLICK, ///< mouse button is released, pending double click
+ STATE_IN_DOUBLE_IGNORE, ///< mouse button is down following double click
+ STATE_IN_DRAG
+ }; ///< mouse button is down during a drag
+
+ BUTTON_STATE m_state;
+ unsigned int m_time;
+ int m_x;
+ int m_y;
+ };
+
+ /*! \brief detect whether the mouse has moved
+
+ Uses a trigger threshold of 2 pixels to detect mouse movement
+
+ \return whether the mouse has moved past the trigger threshold.
+ */
+ bool MovedPastThreshold() const;
+
+ // state of the mouse
+ MOUSE_STATE m_pointerState{MOUSE_STATE_NORMAL};
+ MouseState m_mouseState{};
+ bool m_mouseEnabled;
+ CButtonState m_buttonState[MOUSE_MAX_BUTTON];
+
+ int m_maxX{0};
+ int m_maxY{0};
+ float m_speedX{0.0f};
+ float m_speedY{0.0f};
+
+ // active/click timers
+ unsigned int m_lastActiveTime;
+
+ bool bClick[MOUSE_MAX_BUTTON]{};
+ bool bDoubleClick[MOUSE_MAX_BUTTON]{};
+ HoldAction m_hold[MOUSE_MAX_BUTTON]{};
+ bool bLongClick[MOUSE_MAX_BUTTON]{};
+
+ uint32_t m_Key;
+};
diff --git a/xbmc/input/mouse/MouseTranslator.cpp b/xbmc/input/mouse/MouseTranslator.cpp
new file mode 100644
index 0000000..b5cac7d
--- /dev/null
+++ b/xbmc/input/mouse/MouseTranslator.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2017-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "MouseTranslator.h"
+
+#include "MouseStat.h"
+#include "input/Key.h"
+#include "utils/StringUtils.h"
+#include "utils/XBMCTinyXML.h"
+#include "utils/log.h"
+
+#include <map>
+#include <string>
+
+using namespace KODI;
+using namespace MOUSE;
+
+namespace
+{
+
+using ActionName = std::string;
+using KeyID = uint32_t;
+
+static const std::map<ActionName, KeyID> MouseKeys = {{"click", KEY_MOUSE_CLICK},
+ {"leftclick", KEY_MOUSE_CLICK},
+ {"rightclick", KEY_MOUSE_RIGHTCLICK},
+ {"middleclick", KEY_MOUSE_MIDDLECLICK},
+ {"doubleclick", KEY_MOUSE_DOUBLE_CLICK},
+ {"longclick", KEY_MOUSE_LONG_CLICK},
+ {"wheelup", KEY_MOUSE_WHEEL_UP},
+ {"wheeldown", KEY_MOUSE_WHEEL_DOWN},
+ {"mousemove", KEY_MOUSE_MOVE},
+ {"mousedrag", KEY_MOUSE_DRAG},
+ {"mousedragstart", KEY_MOUSE_DRAG_START},
+ {"mousedragend", KEY_MOUSE_DRAG_END},
+ {"mouserdrag", KEY_MOUSE_RDRAG},
+ {"mouserdragstart", KEY_MOUSE_RDRAG_START},
+ {"mouserdragend", KEY_MOUSE_RDRAG_END}};
+
+} // anonymous namespace
+
+uint32_t CMouseTranslator::TranslateCommand(const TiXmlElement* pButton)
+{
+ uint32_t buttonId = 0;
+
+ if (pButton != nullptr)
+ {
+ std::string szKey = pButton->ValueStr();
+ if (!szKey.empty())
+ {
+ StringUtils::ToLower(szKey);
+
+ auto it = MouseKeys.find(szKey);
+ if (it != MouseKeys.end())
+ buttonId = it->second;
+
+ if (buttonId == 0)
+ {
+ CLog::Log(LOGERROR, "Unknown mouse action ({}), skipping", pButton->Value());
+ }
+ else
+ {
+ int id = 0;
+ if ((pButton->QueryIntAttribute("id", &id) == TIXML_SUCCESS))
+ {
+ if (0 <= id && id < MOUSE_MAX_BUTTON)
+ buttonId += id;
+ }
+ }
+ }
+ }
+
+ return buttonId;
+}
+
+bool CMouseTranslator::TranslateEventID(unsigned int eventId, BUTTON_ID& buttonId)
+{
+ switch (eventId)
+ {
+ case XBMC_BUTTON_LEFT:
+ {
+ buttonId = BUTTON_ID::LEFT;
+ return true;
+ }
+ case XBMC_BUTTON_MIDDLE:
+ {
+ buttonId = BUTTON_ID::MIDDLE;
+ return true;
+ }
+ case XBMC_BUTTON_RIGHT:
+ {
+ buttonId = BUTTON_ID::RIGHT;
+ return true;
+ }
+ case XBMC_BUTTON_WHEELUP:
+ {
+ buttonId = BUTTON_ID::WHEEL_UP;
+ return true;
+ }
+ case XBMC_BUTTON_WHEELDOWN:
+ {
+ buttonId = BUTTON_ID::WHEEL_DOWN;
+ return true;
+ }
+ case XBMC_BUTTON_X1:
+ {
+ buttonId = BUTTON_ID::BUTTON4;
+ return true;
+ }
+ case XBMC_BUTTON_X2:
+ {
+ buttonId = BUTTON_ID::BUTTON5;
+ return true;
+ }
+ case XBMC_BUTTON_X3:
+ {
+ buttonId = BUTTON_ID::HORIZ_WHEEL_LEFT;
+ return true;
+ }
+ case XBMC_BUTTON_X4:
+ {
+ buttonId = BUTTON_ID::HORIZ_WHEEL_RIGHT;
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
diff --git a/xbmc/input/mouse/MouseTranslator.h b/xbmc/input/mouse/MouseTranslator.h
new file mode 100644
index 0000000..e3d4d4b
--- /dev/null
+++ b/xbmc/input/mouse/MouseTranslator.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "MouseTypes.h"
+
+#include <stdint.h>
+
+class TiXmlElement;
+
+class CMouseTranslator
+{
+public:
+ /*!
+ * \brief Translate a keymap element to a key ID
+ */
+ static uint32_t TranslateCommand(const TiXmlElement* pButton);
+
+ /*!
+ * \brief Translate a mouse event ID to a mouse button index
+ *
+ * \param eventId The event ID from MouseStat.h
+ * \param[out] buttonId The button ID from MouseTypes.h, or unmodified if unsuccessful
+ *
+ * \return True if successful, false otherwise
+ */
+ static bool TranslateEventID(unsigned int eventId, KODI::MOUSE::BUTTON_ID& buttonId);
+};
diff --git a/xbmc/input/mouse/MouseTypes.h b/xbmc/input/mouse/MouseTypes.h
new file mode 100644
index 0000000..f11f7ea
--- /dev/null
+++ b/xbmc/input/mouse/MouseTypes.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "input/InputTypes.h"
+
+#include <string>
+
+namespace KODI
+{
+namespace MOUSE
+{
+/*!
+ * \brief Buttons on a mouse
+ */
+enum class BUTTON_ID
+{
+ UNKNOWN,
+ LEFT,
+ RIGHT,
+ MIDDLE,
+ BUTTON4,
+ BUTTON5,
+ WHEEL_UP,
+ WHEEL_DOWN,
+ HORIZ_WHEEL_LEFT,
+ HORIZ_WHEEL_RIGHT,
+};
+
+/*!
+ * \brief Name of a mouse button
+ *
+ * Names are defined in the mouse's controller profile.
+ */
+using ButtonName = std::string;
+
+/*!
+ * \brief Directions of motion for a mouse pointer
+ */
+using POINTER_DIRECTION = INPUT::CARDINAL_DIRECTION;
+
+/*!
+ * \brief Name of the mouse pointer
+ *
+ * Names are defined in the mouse's controller profile.
+ */
+using PointerName = std::string;
+} // namespace MOUSE
+} // namespace KODI
diff --git a/xbmc/input/mouse/generic/CMakeLists.txt b/xbmc/input/mouse/generic/CMakeLists.txt
new file mode 100644
index 0000000..b5c2858
--- /dev/null
+++ b/xbmc/input/mouse/generic/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(SOURCES MouseInputHandling.cpp)
+
+set(HEADERS MouseInputHandling.h)
+
+core_add_library(input_mouse_generic)
diff --git a/xbmc/input/mouse/generic/MouseInputHandling.cpp b/xbmc/input/mouse/generic/MouseInputHandling.cpp
new file mode 100644
index 0000000..0f51ede
--- /dev/null
+++ b/xbmc/input/mouse/generic/MouseInputHandling.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2016-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "MouseInputHandling.h"
+
+#include "input/InputTranslator.h"
+#include "input/joysticks/interfaces/IButtonMap.h"
+#include "input/mouse/interfaces/IMouseInputHandler.h"
+
+using namespace KODI;
+using namespace MOUSE;
+
+CMouseInputHandling::CMouseInputHandling(IMouseInputHandler* handler,
+ JOYSTICK::IButtonMap* buttonMap)
+ : m_handler(handler), m_buttonMap(buttonMap)
+{
+}
+
+bool CMouseInputHandling::OnPosition(int x, int y)
+{
+ using namespace JOYSTICK;
+
+ if (!m_bHasPosition)
+ {
+ m_bHasPosition = true;
+ m_x = x;
+ m_y = y;
+ return true;
+ }
+
+ int dx = x - m_x;
+ int dy = y - m_y;
+
+ bool bHandled = false;
+
+ // Get direction of motion
+ POINTER_DIRECTION dir = GetPointerDirection(dx, dy);
+
+ CDriverPrimitive source(dir);
+ if (source.IsValid())
+ {
+ // Get pointer in direction of motion
+ PointerName pointerName;
+ if (m_buttonMap->GetFeature(source, pointerName))
+ {
+ // Get orthogonal direction of motion
+ POINTER_DIRECTION dirCCW = GetOrthogonalDirectionCCW(dir);
+
+ // Get mapped directions of motion for rotation and reflection
+ CDriverPrimitive target;
+ CDriverPrimitive targetCCW;
+
+ if (m_buttonMap->GetRelativePointer(pointerName, dir, target))
+ m_buttonMap->GetRelativePointer(pointerName, dirCCW, targetCCW);
+
+ if (target.IsValid())
+ {
+ // Invert y to right-handed cartesian system
+ dy *= -1;
+
+ // Perform rotation
+ int rotation[2][2] = {{1, 0}, {0, 1}};
+
+ GetRotation(dir, target.PointerDirection(), rotation);
+
+ dx = rotation[0][0] * dx + rotation[0][1] * dy;
+ dy = rotation[1][0] * dx + rotation[1][1] * dy;
+
+ if (targetCCW.IsValid())
+ {
+ // Perform reflection
+ int reflection[2][2] = {{1, 0}, {0, 1}};
+
+ GetReflectionCCW(target.PointerDirection(), targetCCW.PointerDirection(), reflection);
+
+ dx = reflection[0][0] * dx + reflection[0][1] * dy;
+ dy = reflection[1][0] * dx + reflection[1][1] * dy;
+ }
+
+ // Invert y back to left-handed coordinate system
+ dy *= -1;
+ }
+
+ bHandled = m_handler->OnMotion(pointerName, dx, dy);
+ }
+ }
+ else
+ {
+ // Don't fall through - might disrupt the game
+ bHandled = true;
+ }
+
+ m_x = x;
+ m_y = y;
+
+ return bHandled;
+}
+
+bool CMouseInputHandling::OnButtonPress(BUTTON_ID button)
+{
+ bool bHandled = false;
+
+ JOYSTICK::CDriverPrimitive source(button);
+
+ ButtonName buttonName;
+ if (m_buttonMap->GetFeature(source, buttonName))
+ bHandled = m_handler->OnButtonPress(buttonName);
+
+ return bHandled;
+}
+
+void CMouseInputHandling::OnButtonRelease(BUTTON_ID button)
+{
+ JOYSTICK::CDriverPrimitive source(button);
+
+ ButtonName buttonName;
+ if (m_buttonMap->GetFeature(source, buttonName))
+ m_handler->OnButtonRelease(buttonName);
+}
+
+POINTER_DIRECTION CMouseInputHandling::GetPointerDirection(int x, int y)
+{
+ using namespace INPUT;
+
+ return CInputTranslator::VectorToCardinalDirection(static_cast<float>(x), static_cast<float>(-y));
+}
+
+POINTER_DIRECTION CMouseInputHandling::GetOrthogonalDirectionCCW(POINTER_DIRECTION direction)
+{
+ switch (direction)
+ {
+ case POINTER_DIRECTION::RIGHT:
+ return POINTER_DIRECTION::UP;
+ case POINTER_DIRECTION::UP:
+ return POINTER_DIRECTION::LEFT;
+ case POINTER_DIRECTION::LEFT:
+ return POINTER_DIRECTION::DOWN;
+ case POINTER_DIRECTION::DOWN:
+ return POINTER_DIRECTION::RIGHT;
+ default:
+ break;
+ }
+
+ return POINTER_DIRECTION::NONE;
+}
+
+void CMouseInputHandling::GetRotation(POINTER_DIRECTION source,
+ POINTER_DIRECTION target,
+ int (&rotation)[2][2])
+{
+ switch (source)
+ {
+ case POINTER_DIRECTION::RIGHT:
+ {
+ switch (target)
+ {
+ case POINTER_DIRECTION::UP:
+ GetRotation(90, rotation);
+ break;
+ case POINTER_DIRECTION::LEFT:
+ GetRotation(180, rotation);
+ break;
+ case POINTER_DIRECTION::DOWN:
+ GetRotation(270, rotation);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case POINTER_DIRECTION::UP:
+ {
+ switch (target)
+ {
+ case POINTER_DIRECTION::LEFT:
+ GetRotation(90, rotation);
+ break;
+ case POINTER_DIRECTION::DOWN:
+ GetRotation(180, rotation);
+ break;
+ case POINTER_DIRECTION::RIGHT:
+ GetRotation(270, rotation);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case POINTER_DIRECTION::LEFT:
+ {
+ switch (target)
+ {
+ case POINTER_DIRECTION::DOWN:
+ GetRotation(90, rotation);
+ break;
+ case POINTER_DIRECTION::RIGHT:
+ GetRotation(180, rotation);
+ break;
+ case POINTER_DIRECTION::UP:
+ GetRotation(270, rotation);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case POINTER_DIRECTION::DOWN:
+ {
+ switch (target)
+ {
+ case POINTER_DIRECTION::RIGHT:
+ GetRotation(90, rotation);
+ break;
+ case POINTER_DIRECTION::UP:
+ GetRotation(180, rotation);
+ break;
+ case POINTER_DIRECTION::LEFT:
+ GetRotation(270, rotation);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void CMouseInputHandling::GetRotation(int deg, int (&rotation)[2][2])
+{
+ switch (deg)
+ {
+ case 90:
+ {
+ rotation[0][0] = 0;
+ rotation[0][1] = -1;
+ rotation[1][0] = 1;
+ rotation[1][1] = 0;
+ break;
+ }
+ case 180:
+ {
+ rotation[0][0] = -1;
+ rotation[0][1] = 0;
+ rotation[1][0] = 0;
+ rotation[1][1] = -1;
+ break;
+ }
+ case 270:
+ {
+ rotation[0][0] = 0;
+ rotation[0][1] = 1;
+ rotation[1][0] = -1;
+ rotation[1][1] = 0;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void CMouseInputHandling::GetReflectionCCW(POINTER_DIRECTION source,
+ POINTER_DIRECTION target,
+ int (&rotation)[2][2])
+{
+ switch (source)
+ {
+ case POINTER_DIRECTION::RIGHT:
+ {
+ switch (target)
+ {
+ case POINTER_DIRECTION::DOWN:
+ GetReflection(0, rotation);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case POINTER_DIRECTION::UP:
+ {
+ switch (target)
+ {
+ case POINTER_DIRECTION::RIGHT:
+ GetReflection(90, rotation);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case POINTER_DIRECTION::LEFT:
+ {
+ switch (target)
+ {
+ case POINTER_DIRECTION::UP:
+ GetReflection(180, rotation);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case POINTER_DIRECTION::DOWN:
+ {
+ switch (target)
+ {
+ case POINTER_DIRECTION::LEFT:
+ GetReflection(270, rotation);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void CMouseInputHandling::GetReflection(int deg, int (&reflection)[2][2])
+{
+ switch (deg)
+ {
+ case 0:
+ case 180:
+ {
+ reflection[0][0] = 1;
+ reflection[0][1] = 0;
+ reflection[1][0] = 0;
+ reflection[1][1] = -1;
+ break;
+ }
+ case 90:
+ case 270:
+ {
+ reflection[0][0] = -1;
+ reflection[0][1] = 0;
+ reflection[1][0] = 0;
+ reflection[1][1] = 1;
+ break;
+ }
+ default:
+ break;
+ }
+}
diff --git a/xbmc/input/mouse/generic/MouseInputHandling.h b/xbmc/input/mouse/generic/MouseInputHandling.h
new file mode 100644
index 0000000..6d19da9
--- /dev/null
+++ b/xbmc/input/mouse/generic/MouseInputHandling.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "input/mouse/MouseTypes.h"
+#include "input/mouse/interfaces/IMouseDriverHandler.h"
+
+namespace KODI
+{
+namespace JOYSTICK
+{
+class IButtonMap;
+}
+
+namespace MOUSE
+{
+class IMouseInputHandler;
+
+/*!
+ * \ingroup mouse
+ * \brief Class to translate input from driver info to higher-level features
+ */
+class CMouseInputHandling : public IMouseDriverHandler
+{
+public:
+ CMouseInputHandling(IMouseInputHandler* handler, JOYSTICK::IButtonMap* buttonMap);
+
+ ~CMouseInputHandling(void) override = default;
+
+ // implementation of IMouseDriverHandler
+ bool OnPosition(int x, int y) override;
+ bool OnButtonPress(BUTTON_ID button) override;
+ void OnButtonRelease(BUTTON_ID button) override;
+
+private:
+ // Utility functions
+ static POINTER_DIRECTION GetPointerDirection(int x, int y);
+ static POINTER_DIRECTION GetOrthogonalDirectionCCW(POINTER_DIRECTION direction);
+
+ static void GetRotation(POINTER_DIRECTION source,
+ POINTER_DIRECTION target,
+ int (&rotation)[2][2]);
+ static void GetRotation(int deg, int (&rotation)[2][2]);
+
+ static void GetReflectionCCW(POINTER_DIRECTION source,
+ POINTER_DIRECTION target,
+ int (&reflection)[2][2]);
+ static void GetReflection(int deg, int (&reflection)[2][2]);
+
+ // Construction parameters
+ IMouseInputHandler* const m_handler;
+ JOYSTICK::IButtonMap* const m_buttonMap;
+
+ // Mouse parameters
+ bool m_bHasPosition = false;
+ int m_x = 0;
+ int m_y = 0;
+};
+} // namespace MOUSE
+} // namespace KODI
diff --git a/xbmc/input/mouse/interfaces/IMouseDriverHandler.h b/xbmc/input/mouse/interfaces/IMouseDriverHandler.h
new file mode 100644
index 0000000..7989e39
--- /dev/null
+++ b/xbmc/input/mouse/interfaces/IMouseDriverHandler.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "input/mouse/MouseTypes.h"
+
+namespace KODI
+{
+namespace MOUSE
+{
+/*!
+ * \ingroup mouse
+ * \brief Interface for handling mouse driver events
+ */
+class IMouseDriverHandler
+{
+public:
+ virtual ~IMouseDriverHandler(void) = default;
+
+ /*!
+ * \brief Handle mouse position updates
+ *
+ * \param x The new x coordinate of the pointer
+ * \param y The new y coordinate of the pointer
+ *
+ * The mouse uses a left-handed (graphics) cartesian coordinate system.
+ * Positive X is right, positive Y is down.
+ *
+ * \return True if the event was handled, false otherwise
+ */
+ virtual bool OnPosition(int x, int y) = 0;
+
+ /*!
+ * \brief A mouse button has been pressed
+ *
+ * \param button The index of the pressed button
+ *
+ * \return True if the event was handled, otherwise false
+ */
+ virtual bool OnButtonPress(BUTTON_ID button) = 0;
+
+ /*!
+ * \brief A mouse button has been released
+ *
+ * \param button The index of the released button
+ */
+ virtual void OnButtonRelease(BUTTON_ID button) = 0;
+};
+} // namespace MOUSE
+} // namespace KODI
diff --git a/xbmc/input/mouse/interfaces/IMouseInputHandler.h b/xbmc/input/mouse/interfaces/IMouseInputHandler.h
new file mode 100644
index 0000000..910ddd4
--- /dev/null
+++ b/xbmc/input/mouse/interfaces/IMouseInputHandler.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include "input/mouse/MouseTypes.h"
+
+#include <string>
+
+namespace KODI
+{
+namespace MOUSE
+{
+/*!
+ * \ingroup mouse
+ * \brief Interface for handling mouse events
+ */
+class IMouseInputHandler
+{
+public:
+ virtual ~IMouseInputHandler(void) = default;
+
+ /*!
+ * \brief The controller profile for this mouse input handler
+ *
+ * \return The ID of the add-on extending kodi.game.controller
+ */
+ virtual std::string ControllerID(void) const = 0;
+
+ /*!
+ * \brief A relative pointer has moved
+ *
+ * \param relpointer The name of the relative pointer being moved
+ * \param dx The relative x coordinate of motion
+ * \param dy The relative y coordinate of motion
+ *
+ * The mouse uses a left-handed (graphics) cartesian coordinate system.
+ * Positive X is right, positive Y is down.
+ *
+ * \return True if the event was handled, otherwise false
+ */
+ virtual bool OnMotion(const PointerName& relpointer, int dx, int dy) = 0;
+
+ /*!
+ * \brief A mouse button has been pressed
+ *
+ * \param button The name of the feature being pressed
+ *
+ * \return True if the event was handled, otherwise false
+ */
+ virtual bool OnButtonPress(const ButtonName& button) = 0;
+
+ /*!
+ * \brief A mouse button has been released
+ *
+ * \param button The name of the feature being released
+ */
+ virtual void OnButtonRelease(const ButtonName& button) = 0;
+};
+} // namespace MOUSE
+} // namespace KODI
diff --git a/xbmc/input/mouse/interfaces/IMouseInputProvider.h b/xbmc/input/mouse/interfaces/IMouseInputProvider.h
new file mode 100644
index 0000000..f289070
--- /dev/null
+++ b/xbmc/input/mouse/interfaces/IMouseInputProvider.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+namespace KODI
+{
+namespace MOUSE
+{
+class IMouseInputHandler;
+
+/*!
+ * \ingroup mouse
+ * \brief Interface for classes that can provide mouse input
+ */
+class IMouseInputProvider
+{
+public:
+ virtual ~IMouseInputProvider() = default;
+
+ /*!
+ * \brief Registers a handler to be called on mouse input
+ *
+ * \param handler The handler to receive mouse input provided by this class
+ * \param bPromiscuous True to observe all events without affecting
+ * subsequent handlers
+ */
+ virtual void RegisterMouseHandler(IMouseInputHandler* handler, bool bPromiscuous) = 0;
+
+ /*!
+ * \brief Unregisters handler from mouse input
+ *
+ * \param handler The handler that was receiving mouse input
+ */
+ virtual void UnregisterMouseHandler(IMouseInputHandler* handler) = 0;
+};
+} // namespace MOUSE
+} // namespace KODI